Bzoj3730 震波

Time Limit: 15 Sec  Memory Limit: 256 MB
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

8 1
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

11100101

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 }
View Code

 

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 }

 

转载于:https://www.cnblogs.com/SilverNebula/p/6422348.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值