Bzoj3730 震波
Submit: 753 Solved: 176
Description
在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。
Input
第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。
Output
包含若干行,对于每个询问输出一行一个正整数表示答案。
Sample Input
1 10 100 1000 10000 100000 1000000 10000000
1 2
1 3
2 4
2 5
3 6
3 7
3 8
0 3 1
Sample Output
HINT
1<=N,M<=100000
1<=u,v,x<=N
1<=value[i],y<=10000
0<=k<=N-1
Source
传说中的动态点分治
记录下每个点x的parent结点(即管辖x的分治结点),每次修改时暴力修改这些点。由于分治的性质,最多需要修改logN个结点。
建好分治树后,用树状数组以距离为下标维护:和点x的距离为[下标]的点的权值和。为了去重,需要开两个树状数组,一个维护当前点到当前分治中心的答案,一个维护当前点到上一次分治中心,利用容斥原理计算。
写了大半天,累。敲完代码先花了好久来查错,之后是无尽的TLE。
大概是常数太大了,优化失败,只能放弃。之后看了别人的模板,重写了一遍,又开始长久的调试……
↑这里遇到一个超大的坑:dev c++重构代码之后选了重新编译,它竟然没有替换掉旧的exe文件!(可能是版本问题),我对照着旧代码的exe文件改新代码,怪不得怎么改都没效果……浪费了半个钟头才察觉到这一问题,比较绝望。
排除问题之后,总算是A掉了,跑了9s
----第二天早晨,翻出了刚开始那版代码,觉得还有小地方可以优化,又试了试——居然14.6秒卡过去了……就很气
RE+TLE加起来刷了9条……一半是因为dev的bug
14.6s的超慢代码
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int mxn=200010; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 struct edge{ 17 int v,nxt; 18 }e[mxn<<1]; 19 int hd[mxn],mct=0; 20 void add_edge(int u,int v){ 21 e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return; 22 } 23 int n,m; 24 int w[mxn]; 25 // 26 int fa[mxn][20]; 27 int L_dep[mxn]; 28 void LCA_DFS(int u,int ff){ 29 L_dep[u]=L_dep[ff]+1; 30 for(int i=hd[u];i;i=e[i].nxt){ 31 if(e[i].v==ff)continue; 32 fa[e[i].v][0]=u; 33 LCA_DFS(e[i].v,u); 34 } 35 return; 36 } 37 void LCA_init(){ 38 for(int i=1;i<=18;i++) 39 for(int j=1;j<=n;j++) 40 fa[j][i]=fa[fa[j][i-1]][i-1]; 41 return; 42 } 43 int LCA(int x,int y){ 44 if(L_dep[x]<L_dep[y])swap(x,y); 45 for(int i=18;i>=0;i--) 46 if(L_dep[fa[x][i]]>=L_dep[y])x=fa[x][i]; 47 if(x==y)return y; 48 for(int i=18;i>=0;i--) 49 if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];} 50 return fa[x][0]; 51 } 52 int dist(int x,int y){ 53 int tmp=LCA(x,y); 54 return L_dep[x]-L_dep[tmp]*2+L_dep[y]; 55 } 56 // 57 vector<int>t[mxn][2]; 58 void update(int x,int y,int pos,int v){//结点 模式 位置 增加值 59 // printf("update:%d %d pos:%d v:%d\n",x,y,pos,v); 60 int ed=t[x][y].size()-1;++pos; 61 for(int i=pos;i<=ed;i+=i&-i)t[x][y][i]+=v; 62 return; 63 } 64 int query(int x,int y,int pos){ 65 int size=t[x][y].size(); 66 int st=min(pos+1,size-1); 67 int res=0; 68 for(int i=st;i;i-=i&-i)res+=t[x][y][i]; 69 return res; 70 } 71 // 72 int dep[mxn],sz[mxn],mc[mxn],rt; 73 int pr[mxn]; 74 int smm; 75 bool vis[mxn]; 76 void DFS_sz(int u,int fa){ 77 sz[u]=1;mc[u]=0; 78 for(int i=hd[u];i;i=e[i].nxt){ 79 int v=e[i].v; 80 if(v==fa || vis[v])continue; 81 DFS_sz(v,u); 82 sz[u]+=sz[v]; 83 mc[u]=max(mc[u],sz[v]); 84 } 85 mc[u]=max(mc[u],smm-mc[u]); 86 if(mc[u]<mc[rt])rt=u; 87 return; 88 } 89 void add(int u,int rot,int fa){ 90 // printf("add: u:%d rot:%d fa:%d\n",u,rot,fa); 91 // printf("dist:%d\n",dist(u,rot)); 92 update(rot,0,dist(u,rot),w[u]); 93 if(pr[rot])update(rot,1,dist(u,pr[rot]),w[u]); 94 for(int i=hd[u];i;i=e[i].nxt){ 95 int v=e[i].v; 96 if(vis[v] || v==fa)continue; 97 add(v,rot,u); 98 } 99 return; 100 } 101 void solve(int x,int fa){ 102 // printf("solving:%d %d\n",x,fa); 103 vis[x]=1;pr[x]=fa; 104 t[x][0].resize(smm+5); 105 t[x][1].resize(smm+5); 106 add(x,x,0); 107 for(int i=hd[x];i;i=e[i].nxt){ 108 int v=e[i].v; 109 if(vis[v])continue; 110 smm=sz[v]; 111 rt=0; 112 DFS_sz(v,x); 113 solve(rt,x); 114 } 115 return; 116 } 117 void Upd(int x,int v){ 118 for(int y=x;y;y=pr[y]){ 119 update(y,0,dist(x,y),v-w[x]); 120 if(pr[y])update(y,1,dist(x,pr[y]),v-w[x]); 121 } 122 return; 123 } 124 int Que(int x,int k){ 125 // printf("QUE:%d %d\n",x,k); 126 int res=0;res+=query(x,0,k); 127 // printf("res:%d\n",res); 128 for(int y=x;pr[y];y=pr[y]){ 129 int dd=dist(x,pr[y]); 130 if(k<dd)continue; 131 res+=query(pr[y],0,k-dd); 132 // printf("r1:%d\n",res); 133 res-=query(y,1,k-dd); 134 // printf("r2:%d\n",res); 135 } 136 // int di=dist(x,pr[x]); 137 // if(pr[x] && di<k)res-=query(x,1,k-di); 138 // if(pr[x] && di<k)res+=Que(pr[x],k-di); 139 return res; 140 } 141 // 142 int main(){ 143 int i,j,u,v; 144 int last=0; 145 n=read();m=read(); 146 for(i=1;i<=n;i++)w[i]=read(); 147 for(i=1;i<n;i++){ 148 u=read();v=read(); 149 add_edge(u,v); 150 add_edge(v,u); 151 } 152 mc[rt=0]=1e8; 153 smm=n; 154 LCA_DFS(1,0); 155 LCA_init(); 156 DFS_sz(1,0); 157 solve(rt,0); 158 // 159 int x,y,k,op; 160 while(m--){ 161 op=read();x=read();x^=last; 162 if(op){//update 163 y=read()^last; 164 Upd(x,y); 165 w[x]=y; 166 } 167 else{//query 168 k=read()^last; 169 last=Que(x,k); 170 printf("%d\n",last); 171 } 172 } 173 return 0; 174 }
8.9s的略快代码
那个getship()是从别处学来的,感觉思路清奇
1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int mxn=120010; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 struct edge{ 17 int v,nxt; 18 }e[mxn<<1]; 19 int hd[mxn],mct=0; 20 void add_edge(int u,int v){ 21 e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return; 22 } 23 int n,m; 24 int w[mxn]; 25 // 26 int sz[mxn],mc[mxn],rt,smm; 27 int fa[mxn][20],dis[mxn][20],dep[mxn]; 28 vector<int>t[mxn][2]; 29 bool vis[mxn]; 30 void DFS_sz(int u,int fa){ 31 sz[u]=1;mc[u]=0; 32 for(int i=hd[u];i;i=e[i].nxt){ 33 int v=e[i].v;if(v==fa || vis[v])continue; 34 DFS_sz(v,u); 35 sz[u]+=sz[v]; 36 mc[u]=max(mc[u],sz[v]); 37 } 38 mc[u]=max(mc[u],smm-sz[u]); 39 if(mc[u]<mc[rt])rt=u; 40 return; 41 } 42 void getship(int u,int an,int ff,int d){ 43 for(int i=hd[u];i;i=e[i].nxt){ 44 int v=e[i].v;if(vis[v] || v==ff)continue; 45 fa[v][++dep[v]]=an; 46 dis[v][dep[v]]=d; 47 getship(v,an,u,d+1); 48 } 49 return; 50 } 51 void solve(int x){ 52 vis[x]=1; 53 getship(x,x,0,1); 54 t[x][0].resize(smm+3);t[x][1].resize(smm+3); 55 int tmp=smm; 56 for(int i=hd[x];i;i=e[i].nxt){ 57 int v=e[i].v; 58 if(vis[v])continue; 59 smm=sz[v];if(smm>sz[x])smm=tmp-sz[x]; 60 rt=0; 61 DFS_sz(v,x); 62 solve(rt); 63 } 64 return; 65 } 66 // 67 void add(int x,int y,int pos,int v){ 68 int ed=t[x][y].size()-1; 69 for(int i=pos;i && i<=ed;i+=i&-i)t[x][y][i]+=v; 70 return; 71 } 72 int qsum(int x,int y,int k){ 73 int res=0; 74 if(!y)res+=w[x]; 75 int size=t[x][y].size()-1; 76 k=min(k,size); 77 for(int i=k;i;i-=i&-i)res+=t[x][y][i]; 78 return res; 79 } 80 void Upd(int x,int v){ 81 add(x,1,dis[x][dep[x]],v); 82 for(int i=dep[x];i;i--){ 83 add(fa[x][i],0,dis[x][i],v); 84 add(fa[x][i],1,dis[x][i-1],v); 85 } 86 return; 87 } 88 int Que(int x,int k){ 89 int res=qsum(x,0,k); 90 for(int i=dep[x];i;i--) 91 if(dis[x][i]<=k){ 92 res+=qsum(fa[x][i],0,k-dis[x][i])-qsum(fa[x][i+1],1,k-dis[x][i]); 93 } 94 return res; 95 } 96 // 97 int main(){ 98 int i,j,u,v; 99 n=read();m=read(); 100 for(i=1;i<=n;i++)w[i]=read(); 101 for(i=1;i<n;i++){ 102 u=read();v=read(); 103 add_edge(u,v); 104 add_edge(v,u); 105 } 106 mc[0]=1e8;rt=0; 107 smm=n; 108 DFS_sz(1,0); 109 solve(rt); 110 for(i=1;i<=n;i++)fa[i][dep[i]+1]=i; 111 for(i=1;i<=n;i++)Upd(i,w[i]); 112 int x,y,k,op,last=0; 113 // printf("fin\n");//bug 114 while(m--){ 115 op=read();x=read();x^=last; 116 if(op){//update 117 y=read()^last; 118 Upd(x,y-w[x]); 119 w[x]=y; 120 } 121 else{//query 122 k=read()^last; 123 last=Que(x,k); 124 printf("%d\n",last); 125 } 126 } 127 return 0; 128 }