讲道理我第一次看到动态树分治以为和那个动态树LCT有关QAQ
然而正确的读法是【动态(树分治)】
这就很尴尬了。
题目大意就是给定一棵树,每个点初始权值是0,维护两个操作,一是将和某一个点距离不超过d的点的权值都加上v,二是查询某两个点之间的权值。
首先用点分治建出新的树结构,利用标记永久化的思想为每个点建立一棵线段树记录距离这个点距离为d的点的权值之和,统计的时候再求一下和即可。
唯一要注意的是,为了防止两个节点算重要给每个儿子节点多开开一棵线段树。
/**************************************************************
Problem: 4372
User: RicardoWang
Language: C++
Result: Accepted
Time:22804 ms
Memory:264684 kb
****************************************************************/
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
void _read(int &x)
{
x=0; char ch=getchar(); bool flag=false;
while(ch<'0' || ch>'9'){if(ch=='-')flag=true; ch=getchar();}
while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();} if(flag)x=-x; return ;
}
#define MAXN 200005
struct edge
{
int to,next;
}e[MAXN*2];
int n,m,edge_ct,head[MAXN];
bool del[MAXN];
void add(int x,int y)
{
e[++edge_ct]=(edge){y,head[x]}; head[x]=edge_ct;
e[++edge_ct]=(edge){x,head[y]}; head[y]=edge_ct; return ;
}
int root,sz[MAXN],c[MAXN],f[MAXN],d[MAXN],fb[MAXN][20];
void getroot(int x,int fa,int sum)
{
sz[x]=1; c[x]=0;
for(int id=head[x];id;id=e[id].next)
{
if(e[id].to==fa || del[e[id].to])continue;
getroot(e[id].to,x,sum); sz[x]+=sz[e[id].to]; c[x]=max(c[x],sz[e[id].to]);
}
c[x]=max(sum-sz[x],c[x]);
if(c[x]<c[root])root=x;
return ;
}
void _DFS(int now,int fa)
{
sz[now]=1;
for(int id=head[now];id;id=e[id].next)
{
if(del[e[id].to] || e[id].to==fa)continue;
_DFS(e[id].to,now);
sz[now]+=sz[e[id].to];
}
return ;
}
void _build(int now,int fa,int sum)
{
root=0; getroot(now,0,sum);
int nowroot=root;
del[nowroot]=true; f[nowroot]=fa;
_DFS(nowroot,0);
for(int id=head[nowroot];id;id=e[id].next)
{
if(del[e[id].to])continue;
_build(e[id].to,nowroot,sz[e[id].to]);
}
return ;
}
void DFS_0(int now,int fa)
{
for(int id=head[now];id;id=e[id].next)
{
if(e[id].to==fa)continue;
d[e[id].to]=d[now]+1; f[e[id].to]=now;
DFS_0(e[id].to,now);
}
return ;
}
void makesa()
{
for(int i=1;i<=n;i++)fb[i][0]=f[i];
for(int k=1;k<=17;k++)
{
for(int i=1;i<=n;i++)fb[i][k]=fb[fb[i][k-1]][k-1];
}
return ;
}
int LCA(int x,int y)
{
if(d[x]<d[y])swap(x,y);
for(int k=17;k>=0;k--)if(d[x]-d[y]>=(1<<k))
{
x=fb[x][k];
}
if(x==y)return x;
for(int k=17;k>=0;k--)if(fb[x][k]!=fb[y][k])
{
x=fb[x][k]; y=fb[y][k];
}
return fb[x][0];
}
int getdis(int x,int y)
{
return d[x]+d[y]-2*d[LCA(x,y)];
}
void Init()
{
_read(n); _read(m);
int x,y;
for(int i=1;i<n;i++){_read(x); _read(y); add(x,y);}
DFS_0(1,0);makesa();
memset(f,0,sizeof(f));
c[0]=n+1;_build(1,0,n);
return ;
}
int np,rt1[MAXN],rt2[MAXN],chi[100*MAXN][2],w[100*MAXN];
void update(int &now,int L,int R,int x,int y,int de)
{
if(!now){now=++np; w[now]=0;}
if(x<=L && R<=y){w[now]+=de; return ;}
int m=(L+R)>>1;
if(x<=m)update(chi[now][0],L,m,x,y,de);
if(y>m)update(chi[now][1],m+1,R,x,y,de);
return ;
}
int query(int &now,int L,int R,int x)
{
int ans=w[now];
if(!now || L==R)return w[now];
int m=(L+R)>>1;
return x<=m ? ans+query(chi[now][0],L,m,x): ans+query(chi[now][1],m+1,R,x);
}
void MM(int x,int y,int z)
{
int dis;
update(rt1[x],0,n,0,y,z);
for(int i=x;f[i];i=f[i])
{
dis=getdis(x,f[i]);if(dis>y)continue;
update(rt1[f[i]],0,n,0,y-dis,z);
update(rt2[i],0,n,0,y-dis,z);
}
return ;
}
int QQ(int now)
{
int ans=0,dis;
ans+=query(rt1[now],0,n,0);
for(int i=now;f[i];i=f[i])
{
dis=getdis(f[i],now);
ans+=query(rt1[f[i]],0,n,dis)-query(rt2[i],0,n,dis);
}
return ans;
}
void work()
{
char op;
int x,y,z;
for(int i=1;i<=m;i++)
{
op=getchar(); while(op!='M' && op!='Q')op=getchar();
if(op=='Q')
{
_read(x);
printf("%d\n",QQ(x));
}
else
{
_read(x); _read(y); _read(z); MM(x,y,z);
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
Init();
work();
return 0;
}