1. 程式人生 > >BZOJ 4372/3370 爍爍的遊戲/震波 (動態點分治+線段樹)

BZOJ 4372/3370 爍爍的遊戲/震波 (動態點分治+線段樹)

操作 有效 lca 題目 use 超過 edge truct ini

爍爍的遊戲 題目大意:

給你一棵$n$個節點的樹,有$m$次操作,詢問某個節點的權值,或者將與某個點$x$距離不超過$d$的所有節點的權值都增加$w$

動態點分裸題

每個節點開一棵權值線段樹

對於修改操作,它從$x$開始,像一個漣漪擴散,對它周圍與它距離$\leq d$的所有節點造成$w$點貢獻

為了記錄這個操作的貢獻,我們尋找樹分治每一層中 包含這個節點的那個點分樹的重心$root$

在$root$處記錄貢獻,開一棵動態開點權值線段樹,記錄與這個節點距離為$d$的貢獻總和,顯然在$root$周圍擴散範圍是$d-dis(x,root)$

還要去掉包含$x$子樹的貢獻,所以每個節點要再開一個,記錄對於父重心需要去掉的貢獻

每次查詢都沿著點分重心往上跳,因為修改的過程是在線段樹上打差分,所以在當前重心查詢$d-dis(x,root)$的後綴和即可

由於每次修改都要不斷網上跳重心,一共要修改$log$次,每次都要求距離,所以采用歐拉序求$LCA$減小常數

空間是$O(nlog^{2}n)$的,容易被卡,記錄當前節點最大能擴散的範圍,即當前節點接管的那部分子樹內節點的最大深度,非常有效地優化了空間

實在是講不太明白,大家可以看代碼

  1 #include <map>
  2 #include <queue>
  3 #include <vector>
  4
#include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #define N1 101000 8 #define ll long long 9 #define dd double 10 #define inf 0x3f3f3f3f3f3f3f3fll 11 using namespace std; 12 13 int gint() 14 { 15 int ret=0,fh=1;char c=getchar(); 16 while
(c<0||c>9){if(c==-)fh=-1;c=getchar();} 17 while(c>=0&&c<=9){ret=ret*10+c-0;c=getchar();} 18 return ret*fh; 19 } 20 21 struct SEG{ 22 int sum[N1*150],ls[N1*150],rs[N1*150],rm[N1],rf[N1],tot; 23 void pushup(int rt){sum[rt]=sum[ls[rt]]+sum[rs[rt]];} 24 void update(int x,int l,int r,int &rt,int w) 25 { 26 if(!rt) rt=++tot; 27 if(l==r) {sum[rt]+=w;return;} 28 int mid=(l+r)>>1; 29 if(x<=mid) update(x,l,mid,ls[rt],w); 30 else update(x,mid+1,r,rs[rt],w); 31 pushup(rt); 32 } 33 int query(int L,int R,int l,int r,int rt) 34 { 35 if(!rt) return 0; 36 if(L<=l&&r<=R) return sum[rt]; 37 int mid=(l+r)>>1,ans=0; 38 if(L<=mid) ans+=query(L,R,l,mid,ls[rt]); 39 if(R>mid) ans+=query(L,R,mid+1,r,rs[rt]); 40 return ans; 41 } 42 }s; 43 44 struct Edge{ 45 int to[N1<<1],nxt[N1<<1],head[N1],cte; 46 void ae(int u,int v) 47 {cte++;to[cte]=v,nxt[cte]=head[u],head[u]=cte;} 48 }e; 49 50 int n,m,T; 51 namespace tr{ 52 int dep[N1],ff[N1<<1][20],st[N1],id[N1<<1],lg[N1<<1],tot; 53 void dfs1(int u,int dad) 54 { 55 id[++tot]=u; st[u]=tot; ff[tot][0]=u; 56 for(int j=e.head[u];j;j=e.nxt[j]) 57 { 58 int v=e.to[j]; if(v==dad) continue; 59 dep[v]=dep[u]+1; dfs1(v,u); id[++tot]=u; ff[tot][0]=u; 60 } 61 } 62 void get_st() 63 { 64 int i,j; 65 for(lg[1]=0,i=2;i<=tot;i++) lg[i]=lg[i>>1]+1; 66 for(j=1;j<=lg[tot];j++) 67 for(i=1;i+(1<<j)-1<=tot;i++) 68 ff[i][j]=dep[ ff[i][j-1] ]<dep[ ff[i+(1<<(j-1))][j-1] ]?ff[i][j-1]:ff[i+(1<<(j-1))][j-1]; 69 } 70 int dis(int x,int y) 71 { 72 int tx=min(st[x],st[y]),ty=max(st[x],st[y]),L=ty-tx+1; 73 int fa=dep[ ff[tx][lg[L]] ]<dep[ ff[ty-(1<<lg[L])+1][lg[L]] ]?ff[tx][lg[L]]:ff[ty-(1<<lg[L])+1][lg[L]]; 74 return dep[x]+dep[y]-2*dep[fa]; 75 } 76 void init(){dfs1(1,-1);get_st();} 77 }; 78 79 using tr::dis; 80 81 int ms[N1],sz[N1],dep[N1],mad[N1],use[N1],fa[N1],tsz,G; 82 void dfs(int u,int dad,int g) 83 { 84 mad[g]=max(mad[g],dep[u]); sz[u]=1; 85 for(int j=e.head[u];j;j=e.nxt[j]) 86 { 87 int v=e.to[j]; if(v==dad||use[v]) continue; 88 dep[v]=dep[u]+1; dfs(v,u,g); sz[u]+=sz[v]; 89 } 90 } 91 void gra(int u,int dad) 92 { 93 sz[u]=1; ms[u]=0; 94 for(int j=e.head[u];j;j=e.nxt[j]) 95 { 96 int v=e.to[j]; if(use[v]||v==dad) continue; 97 gra(v,u); sz[u]+=sz[v]; ms[u]=max(ms[u],sz[v]); 98 } 99 ms[u]=max(ms[u],tsz-sz[u]); 100 if(ms[u]<ms[G]) G=u; 101 } 102 void main_dfs(int u) 103 { 104 use[u]=1; dep[u]=0; dfs(u,-1,u); 105 for(int j=e.head[u];j;j=e.nxt[j]) 106 { 107 int v=e.to[j]; if(use[v]) continue; 108 G=0; tsz=sz[v]; gra(v,-1); fa[G]=u; 109 main_dfs(G); 110 } 111 } 112 void modify(int x,int K,int w) 113 { 114 int i,D; 115 for(i=x;i;i=fa[i]) 116 { 117 D=dis(x,i); 118 if(D<=K) s.update(min(mad[i],K-D),0,mad[i],s.rm[i],w); 119 if(!fa[i]) break; 120 D=dis(x,fa[i]); 121 if(D<=K) s.update(min(mad[fa[i]],K-D),0,mad[fa[i]],s.rf[i],w); 122 } 123 } 124 int query(int x) 125 { 126 int i,D,ans=0; 127 for(i=x;i;i=fa[i]) 128 { 129 D=dis(x,i); 130 if(D<=mad[i]) ans+=s.query(D,mad[i],0,mad[i],s.rm[i]); 131 if(!fa[i]) break; 132 D=dis(x,fa[i]); 133 if(D<=mad[fa[i]]) ans-=s.query(D,mad[fa[i]],0,mad[fa[i]],s.rf[i]); 134 } 135 return ans; 136 } 137 138 int main() 139 { 140 scanf("%d%d",&n,&m); 141 int i,j,x,y,w,ans=0; 142 for(i=1;i<n;i++) x=gint(), y=gint(), e.ae(x,y), e.ae(y,x); 143 tr::init(); 144 ms[0]=tsz=n; G=0; gra(1,-1); gra(G,-1); 145 main_dfs(G); char str[10]; 146 for(i=1;i<=m;i++) 147 { 148 scanf("%s",str); 149 if(str[0]==M){ 150 x=gint(); y=gint(); w=gint(); 151 modify(x,y,w); 152 }else{ 153 x=gint(); 154 ans=query(x); 155 printf("%d\n",ans); 156 } 157 } 158 return 0; 159 }

震波那道題和這道題非常像,只不過是點的修改和子樹的查詢

但由於我一直被卡常,沒臉放代碼了qwq

BZOJ 4372/3370 爍爍的遊戲/震波 (動態點分治+線段樹)