[BZOJ]4372: 烁烁的游戏
Time Limit: 30 Sec Memory Limit: 512 MB
Description
背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。
题意:
给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠。
烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠。皮皮鼠会被烁烁吸引,所以会一直待在节点上不动。
烁烁很好奇,在当前时刻,节点u有多少个他的好朋友---皮皮鼠。
大意:
给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:
Q x:询问x的点权。
M x d w:将树上与节点x距离不超过d的节点的点权均加上w。
Input
第一行两个正整数:n,m
接下来的n-1行,每行三个正整数u,v,代表u,v之间有一条边。
接下来的m行,每行给出上述两种操作中的一种。
Output
对于每个Q操作,输出当前x节点的皮皮鼠数量。
Sample Input
7 6
1 2
1 4
1 5
2 3
2 7
5 6
M 1 1 2
Q 5
M 2 2 3
Q 3
M 1 2 1
Q 2
1 2
1 4
1 5
2 3
2 7
5 6
M 1 1 2
Q 5
M 2 2 3
Q 3
M 1 2 1
Q 2
Sample Output
2
3
6
3
6
HINT
数据范围:
n,m<=10^5,|w|<=10^4
注意:w不一定为正整数,因为烁烁可能把皮皮鼠吓傻了。
Solution
动态点分治。先建出点分治的分治结构,修改一个点的时候,对于每一层该点所在的分治结构,开一个线段树在d减该点到重心距离(即到其他子树的最远距离)的位置加上w,查询同样对每一层的线段树查询大等于该点到重心距离的权值和,为了避免统计到自己子树内的信息,每一层分治结构的每个大的子树都再开一个线段树存储子树内信息。总复杂度$O(nlog^{2}n)$。
Code
#include<cstdio> #include<algorithm> using namespace std; inline int read() { int x,f=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')f=0; for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0'; return f?x:-x; } #define MN 100000 #define K 20 #define ND 30000000 struct edge{int nx,t;}e[MN*2+5]; int h[MN+5],en,sz,rt,rts,u[MN+5],s[MN+5]; int fa[MN+5],dep[MN+5],t1[MN+5],t2[K][MN+5],tn,d[K][MN+5]; struct node{int l,r,s;}t[ND+5]; inline void ins(int x,int y) { e[++en]=(edge){h[x],y};h[x]=en; e[++en]=(edge){h[y],x};h[y]=en; } int query(int k,int l,int r,int ql,int qr) { if(l==ql&&r==qr)return t[k].s; int mid=l+r>>1; if(qr<=mid)return query(t[k].l,l,mid,ql,qr); if(ql>mid)return query(t[k].r,mid+1,r,ql,qr); return query(t[k].l,l,mid,ql,mid)+query(t[k].r,mid+1,r,mid+1,qr); } void add(int&k,int l,int r,int x,int ad) { if(!k)k=++tn; if(l==r){t[k].s+=ad;return;} int mid=l+r>>1; if(x<=mid)add(t[k].l,l,mid,x,ad); else add(t[k].r,mid+1,r,x,ad); t[k].s=t[t[k].l].s+t[t[k].r].s; } void getrt(int x,int fa) { int mx=0; s[x]=1; for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa&&!u[e[i].t]) getrt(e[i].t,x),s[x]+=s[e[i].t],mx=max(mx,s[e[i].t]); mx=max(mx,sz-s[x]); if(mx<rts)rts=mx,rt=x; } void dfs(int x,int fa,int dep) { s[x]=1;d[dep][x]=d[dep][fa]+1; for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa&&!u[e[i].t]) t2[dep][e[i].t]=t2[dep][x],dfs(e[i].t,x,dep),s[x]+=s[e[i].t]; } void solve(int x) { int i;u[x]=1; for(i=h[x];i;i=e[i].nx)if(!u[e[i].t]) t2[dep[x]][e[i].t]=++tn,dfs(e[i].t,x,dep[x]); for(i=h[x];i;i=e[i].nx)if(!u[e[i].t]) sz=rts=s[e[i].t],getrt(e[i].t,x), fa[rt]=x,dep[rt]=dep[x]+1,solve(rt); } int main() { int n,m,i,x,y,w;char s[5]; n=read();m=read(); for(i=1;i<n;++i)ins(read(),read()); sz=rts=n;getrt(1,0);solve(rt); while(m--) { scanf("%s",s); if(s[0]=='M') { x=read();y=read();w=read(); for(i=x;i;i=fa[i])if(y>=d[dep[i]][x]) { add(t1[i],0,MN,y-d[dep[i]][x],w); if(t2[dep[i]][x])add(t2[dep[i]][x],0,MN,y-d[dep[i]][x],w); } } else { x=read();w=0; for(i=x;i;i=fa[i]) w+=query(t1[i],0,MN,d[dep[i]][x],MN)-query(t2[dep[i]][x],0,MN,d[dep[i]][x],MN); printf("%d\n",w); } } }