给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:
Q x:询问x的点权
M x d w:将树上与节点x距离不超过d的节点的点权均加上w
dfs出点分树
每个重心要记录这个重心以下的子点分树的修改信息,可以用区间覆盖单店查询的线段树维护,因为会有重复的部分,每个重心还要再开一棵线段树记录重复的部分
#include
#include
#include
#define N 100010
using namespace std;
int n,m,cnt,u,v,mn,isz,id;
int G[N],vis[N],dpt[N],p[N],rt[N],rt1[N];
int fa[N][25];
char op;
struct edge{
int t,nx;
}E[N<<1];
struct sgm{
int l,r,ls,rs,tot,flg;
}T[N*150];
inline void Read(int &x){
char c=getchar();x=0; int f=1;
for(;c>57||c<48;c=getchar())if(c=='-')f=-1;
for(;c>=48&&c<=57;x=x*10+c-48,c=getchar()); x*=f;
}
inline void Insert(int u,int v){
E[++cnt].t=v; E[cnt].nx=G[u]; G[u]=cnt;
E[++cnt].t=u; E[cnt].nx=G[v]; G[v]=cnt;
}
int get_size(int x,int f){
int sz=1;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f&&!vis[E[i].t]) sz+=get_size(E[i].t,x);
return sz;
}
int get_root(int x,int f,int &rt){
int sz=1,maxx=0;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f&&!vis[E[i].t]){
int k=get_root(E[i].t,x,rt);
if(k>maxx) maxx=k;
sz+=k;
}
if(isz-sz>maxx) maxx=isz-sz;
if(maxxreturn sz;
}
int dfs(int x){
isz=get_size(x,0);
mn=1<<30;
int rt;
get_root(x,0,rt); vis[rt]=1;
for(int i=G[rt];i;i=E[i].nx)
if(!vis[E[i].t]) p[dfs(E[i].t)]=rt;
return rt;
}
void explore(int x,int f){
dpt[x]=dpt[f]+1; fa[x][0]=f;
for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f) explore(E[i].t,x);
}
inline int LCA(int x,int y){
if(dpt[x]return LCA(y,x);
for(int i=20;~i;i--)
if(dpt[fa[x][i]]>=dpt[y]) x=fa[x][i];
if(x==y) return x;
for(int i=20;~i;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
inline int dis(int x,int y){
return dpt[x]+dpt[y]-2*dpt[LCA(x,y)];
}
int query(int g,int x){
if(!g) return 0;
if(T[g].l==T[g].r) return T[g].tot;
int mid=T[g].l+T[g].r>>1;
if(x<=mid) return query(T[g].ls,x)+T[g].tot;
else return query(T[g].rs,x)+T[g].tot;
}
inline int query(int x){
int dist=0,r=query(rt[x],dist);
for(int i=x;p[i];i=p[i]){
dist=dis(p[i],x);
r+=query(rt[p[i]],dist)+query(rt1[i],dist);
}
return r;
}
void add(int &g,int L,int R,int l,int r,int v){
if(!g){
g=++id,T[g].l=L,T[g].r=R;
T[g].flg=T[g].tot=0;
}
if(L==l&&r==R){
T[g].tot+=v;
return ;
}
int mid=L+R>>1;
if(r<=mid) add(T[g].ls,L,mid,l,r,v);
else if(l>mid) add(T[g].rs,mid+1,R,l,r,v);
else add(T[g].ls,L,mid,l,mid,v),add(T[g].rs,mid+1,R,mid+1,r,v);
}
inline void add(int x,int d,int v){
int dist;
add(rt[x],0,n,0,d,v);
for(int i=x;p[i];i=p[i]){
dist=dis(p[i],x);
if(dist>d) continue;
add(rt1[i],0,n,0,d-dist,-v);
add(rt[p[i]],0,n,0,d-dist,v);
}
}
int main(){
Read(n); Read(m);
for(int i=1;i1,0);
dfs(1);
for(int i=1;i<=m;i++){
while((op=getchar())!='Q'&&op!='M');
if(op=='Q'){
int x; Read(x);
printf("%d\n",query(x));
}
else{
int x,d,v;
Read(x); Read(d); Read(v);
add(x,d,v);
}
}
return 0;
}