[bzoj4372]烁烁的游戏
来自FallDream的博客,未经允许,请勿转载,谢谢。
背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。
题意:
给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠。
烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠。皮皮鼠会被烁烁吸引,所以会一直待在节点上不动。
烁烁很好奇,在当前时刻,节点u有多少个他的好朋友---皮皮鼠。
大意:
给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:
Q x:询问x的点权。
M x d w:将树上与节点x距离不超过d的节点的点权均加上w。
n,m<=10^5 wi<=10^4
让离树上一个点距离小等于d的点的权值加上一个数,这个是可以点分来做的,每次分治都统计一个子树对其它子树的答案的影响。
这道题就动态点分呗。
先建出分治结构,然后每个分治的子结构开一个线段树维护不同深度的答案。
为了去重,每个分治结构的每个子树还要开一个线段树,表示在这个子树内要去掉的答案。
询问和修改直接从分治结构最底层向上爬,修改或者查询线段树上的值就行了。
复杂度nlog^2n
#include<iostream> #include<cstdio> #define INF 2000000000 #define MN 100000 #define MD 18 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } bool b[MN+5]; int n,m,head[MN+5],cnt=0,mn,rt,tot,dep[MD+5][MN+5],bel[MD+5][MN+5]; int size[MN+5],mx[MN+5],Fa[MD+5][MN+5],Mxdp[MN+5]; struct edge{int to,next;}e[MN*2+5]; struct Tree{int l,r,x;}T[20000000]; inline void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; }; void GetRt(int x,int fa) { size[x]=1;mx[x]=0; for(int i=head[x];i;i=e[i].next) if(!b[e[i].to]&&e[i].to!=fa) { GetRt(e[i].to,x); size[x]+=size[e[i].to]; mx[x]=max(mx[x],size[e[i].to]); } int Sz=max(tot-size[x],mx[x]); if(Sz<mn) mn=Sz,rt=x; } void Dfs(int x,int fa,int Dep) { ++tot; for(int i=head[x];i;i=e[i].next) if(e[i].to!=fa&&!b[e[i].to]) { bel[Dep][e[i].to]=bel[Dep][x]; dep[Dep][e[i].to]=dep[Dep][x]+1; Dfs(e[i].to,x,Dep); } } void Solve(int x,int Dp) { b[x]=1;bel[Dp][x]=++cnt;Mxdp[x]=Dp;dep[Dp][x]=1; for(int i=head[x];i;i=e[i].next) if(!b[e[i].to]) { tot=0;dep[Dp][e[i].to]=2; bel[Dp][e[i].to]=++cnt; Dfs(e[i].to,x,Dp); size[e[i].to]=tot; } for(int i=head[x];i;i=e[i].next) if(!b[e[i].to]) { tot=size[e[i].to];mn=INF; GetRt(e[i].to,x); Fa[Dp+1][rt]=x; Solve(rt,Dp+1); } } int Query(int x,int v,int lt,int rt) { if(!x) return 0; if(lt==rt) return T[x].x; int mid=lt+rt>>1,res; if(v<=mid) res=Query(T[x].l,v,lt,mid); else res=Query(T[x].r,v,mid+1,rt); return res+T[x].x; } inline int node(int x){return x?x:++cnt;} void Modify(int x,int l,int r,int lt,int rt,int v) { if(l==lt&&r==rt) {T[x].x+=v;return;} int mid=lt+rt>>1; if(r<=mid) Modify(T[x].l=node(T[x].l),l,r,lt,mid,v); else if(l>mid) Modify(T[x].r=node(T[x].r),l,r,mid+1,rt,v); else Modify(T[x].l=node(T[x].l),l,mid,lt,mid,v), Modify(T[x].r=node(T[x].r),mid+1,r,mid+1,rt,v); } char op[5]; int main() { n=read();m=read(); for(int i=1;i<n;++i) ins(read(),read()); cnt=0;mn=INF;tot=n;GetRt(1,0);Solve(rt,1); for(int ii=1;ii<=m;++ii) { scanf("%s",op+1); if(op[1]=='Q') { int x=read(),sum=0; for(int j=Mxdp[x],k=x;j;k=Fa[j--][k]) { sum+=Query(bel[j][k],dep[j][x],1,MN); if(j!=Mxdp[x]) sum-=Query(bel[j][x],dep[j][x],1,MN); } printf("%d\n",sum); } else { int x=read(),d=read(),w=read(); for(int j=Mxdp[x],k=x;j;k=Fa[j--][k]) if(d-dep[j][x]+2>=1) { Modify(bel[j][k],1,d-dep[j][x]+2,1,MN,w); if(Mxdp[x]!=j) Modify(bel[j][x],1,d-dep[j][x]+2,1,MN,w); } } } return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream