4372: 烁烁的游戏
动态点分治,其实就是将点分树建出来,然后在树上做一些动态操作(不改变树的形态)。
对于每一个点,我们用线段树存下这个点的子树中所有原树上距离的权值。然后对于修改直接暴力跳父亲,容斥去重就可以了。询问也同样道理。
复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
#include<cmath>
#include<cstdio>
#include<algorithm>
const int MAXN=1e5+5;
int n,m,Ans,tot,Fa[MAXN],TFa[MAXN][20],Dep[MAXN],All,Siz[MAXN],MaxSiz[MAXN],Root;bool vis[MAXN];
int T[2][MAXN],Tre[MAXN*120],Lt[MAXN*120],Rt[MAXN*120];
#include<cctype>
int read(){
int ret=0;char ch=getchar();bool f=1;
for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
for(; isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;
return f?ret:-ret;
}
struct Edge{
int tot,lnk[MAXN],nxt[MAXN<<1],son[MAXN<<1];
void Add(int x,int y){nxt[++tot]=lnk[x];lnk[x]=tot;son[tot]=y;}
}E;
void GetRoot(int x,int fa){
Siz[x]=1;MaxSiz[x]=0;
for(int j=E.lnk[x];j;j=E.nxt[j])
if(E.son[j]!=fa&&!vis[E.son[j]]){
GetRoot(E.son[j],x),Siz[x]+=Siz[E.son[j]];
MaxSiz[x]=std::max(MaxSiz[x],Siz[E.son[j]]);
}
MaxSiz[x]=std::max(All-Siz[x],MaxSiz[x]);
if(MaxSiz[x]<MaxSiz[Root]) Root=x;
}
void Build(int x,int fa){
Fa[x]=fa;vis[x]=1;
for(int j=E.lnk[x];j;j=E.nxt[j])
if(E.son[j]!=fa&&!vis[E.son[j]]) All=Siz[E.son[j]],Root=0,GetRoot(E.son[j],x),Build(Root,x);
}
void DFS(int x,int fa){
TFa[x][0]=fa;Dep[x]=Dep[fa]+1;
for(int j=E.lnk[x];j;j=E.nxt[j]) if(E.son[j]!=fa) DFS(E.son[j],x);
}
void INIT(){
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++) TFa[i][j]=TFa[TFa[i][j-1]][j-1];
}
int LCA(int p,int q){
if(Dep[p]<Dep[q]) std::swap(p,q);
int Del=Dep[p]-Dep[q];
for(int j=0;(1<<j)<=Del;j++) if(Del&(1<<j)) p=TFa[p][j];
if(p==q) return p;
for(int j=log2(n);j>=0;j--)
if(TFa[p][j]!=TFa[q][j]) p=TFa[p][j],q=TFa[q][j];
return TFa[p][0];
}
int GetDist(int x,int y){return Dep[x]+Dep[y]-2*Dep[LCA(x,y)];}
void Insert(int &rt,int L,int R,int x,int p){
if(!rt) rt=++tot;Tre[rt]+=p;
if(L==R) return;int mid=(R+L)>>1;
if(x<=mid) Insert(Lt[rt],L,mid,x,p);
else Insert(Rt[rt],mid+1,R,x,p);
}
int Query(int rt,int L,int R,int l,int r){
if(!rt) return 0;
if(l<=L&&R<=r) return Tre[rt];
int mid=(R+L)>>1,Sum=0;
if(l<=mid) Sum+=Query(Lt[rt],L,mid,l,r);
if(r>mid) Sum+=Query(Rt[rt],mid+1,R,l,r);
return Sum;
}
void Updata(int rt,int x,int d,int w){
int D=GetDist(rt,x);
if(d-D>=0) Insert(T[0][rt],0,n,d-D,w);
if(!Fa[rt]) return;
D=GetDist(Fa[rt],x);
if(d-D>=0) Insert(T[1][rt],0,n,d-D,w);
Updata(Fa[rt],x,d,w);
}
void Ask(int rt,int x){
Ans+=Query(T[0][rt],0,n,GetDist(rt,x),n);
if(!Fa[rt]) return;
Ans-=Query(T[1][rt],0,n,GetDist(Fa[rt],x),n);
Ask(Fa[rt],x);
}
int main(){
// freopen("4372.in","r",stdin);
// freopen("4372.out","w",stdout);
n=read(),m=read();
for(int i=1,x,y;i<n;i++) x=read(),y=read(),E.Add(x,y),E.Add(y,x);
DFS(1,0);INIT();All=n,MaxSiz[0]=1e9,Root=0,GetRoot(1,0),Build(Root,0);
for(int i=1;i<=m;i++){
char ch[10];scanf("%s",ch);
if(ch[0]=='Q'){
int x=read();Ans=0;Ask(x,x);
printf("%d\n",Ans);
}else{
int x=read(),D=read(),w=read();
Updata(x,x,D,w);
}
}
return 0;
}