[bzoj3730] 震波
点分治+线段树。。
对于每个重心,以点到重心的距离建权值线段树,维护点权总和。
修改就在那个点所属的logn棵线段树里改。
但显然查询的时候要考虑去重的问题...
对于当前层的重心,记录一下它在 上一层的重心的哪个儿子 的子树里,等一下查询到上一层的时候要把这部分的去掉(对应子树内的点应该是给这一层的重心算的)。
去掉的话。。就对子树新开一颗线段树,权值是子树内的点到上一层重心的距离。。。累加的时候用这一层的答案减去子树内的答案。
查询的时候,在查询的点所属的logn个重心的线段树里查询,去重如上文。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define ll long long 6 using namespace std; 7 const int maxn=100023,inf=1002333333,mxnode=10000233; 8 struct zs{ 9 int too,pre; 10 }e[maxn<<1];int tot,last[maxn]; 11 int root[maxn<<1],lc[mxnode],rc[mxnode],sm[mxnode],tt; 12 int sz[maxn],mx[maxn],dis[maxn],val[maxn],p[maxn],mxdep[maxn],num,poi,rt; 13 int f[30][maxn],dist[30][maxn]; 14 bool del[maxn]; 15 int i,j,k,n,m; 16 17 int ra;char rx; 18 inline int read(){ 19 rx=getchar(),ra=0; 20 while(rx<'0'||rx>'9')rx=getchar(); 21 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 22 } 23 24 25 void add(int &x,int a,int b,int pos,int val){ 26 if(!x)x=++tt; 27 sm[x]+=val; 28 if(a==b)return; 29 int mid=a+b>>1; 30 if(pos<=mid)add(lc[x],a,mid,pos,val);else add(rc[x],mid+1,b,pos,val); 31 } 32 int que(int x,int a,int b,int K){ 33 if(!x||K>=b)return sm[x]; 34 int mid=a+b>>1; 35 if(K>mid) return sm[lc[x]]+que(rc[x],mid+1,b,K); 36 else return que(lc[x],a,mid,K); 37 } 38 39 40 void getrt(int x,int fa){ 41 sz[x]=1; 42 for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa&&!del[e[i].too]) 43 getrt(e[i].too,x),sz[x]+=sz[e[i].too]; 44 mx[x]=max(sz[x]-1,poi-sz[x]+1); 45 if(mx[x]<mx[rt])rt=x; 46 } 47 void getpoi(int rt,int x,int fa){ 48 add(root[rt],0,n,dis[x],val[x]); 49 for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa&&!del[e[i].too]) 50 p[++num]=e[i].too,dis[e[i].too]=dis[x]+1,getpoi(rt,e[i].too,x); 51 } 52 53 void work(int dep,int x,int next,int precg){ 54 int i,cg;//cg:center of gravity 55 getrt(x,rt=0),cg=rt; 56 if(next!=0)dis[next]=1,num=0,getpoi(cg+n,next,0); 57 58 del[cg]=1,mxdep[cg]=dep; 59 dis[cg]=0,p[num=1]=cg,getpoi(cg,cg,0); 60 for(i=1;i<=num;i++)dist[dep][p[i]]=dis[p[i]],f[dep][p[i]]=cg; 61 62 for(i=last[cg];i;i=e[i].pre)if(!del[e[i].too]) 63 poi=sz[e[i].too],work(dep+1,e[i].too,e[i].too,cg); 64 } 65 inline int query(int x,int K){ 66 int i,ans=que(root[x],0,n,K); 67 for(i=mxdep[x]-1;i;i--) 68 ans+=que(root[f[i][x]],0,n,K-dist[i][x])-que(root[f[i+1][x]+n],0,n,K-dist[i][x]); 69 return ans; 70 } 71 inline void change(int x,int v){ 72 int delta=v-val[x],i,pre=x;val[x]=v; 73 add(root[x],0,n,0,delta); 74 for(i=mxdep[x]-1;i;i--) 75 add(root[f[i][x]],0,n,dist[i][x],delta),add(root[f[i+1][x]+n],0,n,dist[i][x],delta); 76 } 77 inline void insert(int a,int b){ 78 e[++tot].too=b,e[tot].pre=last[a],last[a]=tot; 79 e[++tot].too=a,e[tot].pre=last[b],last[b]=tot; 80 } 81 82 int main(){ 83 mx[0]=inf; 84 n=read(),m=read(); 85 for(i=1;i<=n;i++)val[i]=read(); 86 for(i=1;i<n;i++)insert(read(),read()); 87 poi=n,work(1,1,0,0); 88 89 int id,la=0; 90 while(m--){ 91 id=read(),j=read(),k=read(); 92 j^=la,k^=la; 93 if(id==0)printf("%d\n",la=query(j,k)); 94 else change(j,k); 95 } 96 return 0; 97 }
卡着时限过去的TAT