完全不会写动态点分治,还有救吗?急,在线等
先建出点分树,每个节点$x$存它管辖范围内的所有点,按以$x$为根时的深度为关键字排序
修改$(x,d,w)$:对于$x$在点分树上的祖先$f$,若$\text{dis}_{f,x}\leq d$,则把深度在$\left[0,d-\text{dis}_{f,x}\right]$内的点$+w$
但是这样会算重,考虑容斥,记$f$在点分树上向$x$走一步是$p$,$p$的管辖范围内与$f$在原树中相邻的点为$t$,那么我们需要容斥掉的是以$t$为根,深度在$\left[0,d-\text{dis}_{p,x}-1\right]$内的点
这两个值在每个节点开两个树状数组存就可以了,查询时顺着点分树往上跳顺便统计答案即可
存节点在某棵点分树子树中的标号时用map会被卡常,因为一个点在点分树上只有$O(\log_2n)$个祖先,所以直接开一个$n\times\log_2n$的数组存就可以了
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int inf=2147483647;
int lowbit(int x){return x&-x;}
int h[100010],nex[200010],to[200010],M;
void add(int a,int b){
M++;
to[M]=b;
nex[M]=h[a];
h[a]=M;
}
int dfn[100010],dep[100010],f[200010][18],lg[200010];
void dfs(int fa,int x){
f[++M][0]=x;
dfn[x]=M;
dep[x]=dep[fa]+1;
for(int i=h[x];i;i=nex[i]){
if(to[i]!=fa){
dfs(x,to[i]);
f[++M][0]=x;
}
}
}
int mind(int x,int y){return dep[x]<dep[y]?x:y;}
int query(int l,int r){
int k=lg[r-l+1];
return mind(f[l][k],f[r-(1<<k)+1][k]);
}
int lca(int x,int y){
if(dfn[x]>dfn[y])swap(x,y);
return query(dfn[x],dfn[y]);
}
int dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
struct bit{
int*s,n;
void resize(int x){
n=x;
s=new int[n+1];
memset(s,0,(n+1)<<2);
}
void add(int x,int v){
while(x<=n){
s[x]+=v;
x+=lowbit(x);
}
}
int query(int x){
int res=0;
while(x){
res+=s[x];
x-=lowbit(x);
}
return res;
}
void add(int l,int r,int v){
add(l,v);
if(r<n)add(r+1,-v);
}
}b1[100010],b2[100010];
bool v[100010];
int siz[100010],n;
void dfs1(int fa,int x){
siz[x]=1;
n++;
for(int i=h[x];i;i=nex[i]){
if(to[i]!=fa&&!v[to[i]]){
dfs1(x,to[i]);
siz[x]+=siz[to[i]];
}
}
}
int mn,cn;
void dfs2(int fa,int x){
int i,k=0;
for(i=h[x];i;i=nex[i]){
if(to[i]!=fa&&!v[to[i]]){
dfs2(x,to[i]);
k=max(k,siz[to[i]]);
}
}
k=max(k,n-siz[x]);
if(k<mn){
mn=k;
cn=x;
}
}
int fa[100010];
struct pr{
int x,d;
pr(int a=0,int b=0){x=a;d=b;}
};
bool operator<(pr a,pr b){return a.d==b.d?a.x<b.x:a.d<b.d;}
vector<pr>s1[100010],s2[100010];
vector<pr>::iterator it;
void dfs3(vector&son,int fa,int x,int d){
son.push_back(pr(x,d));
for(int i=h[x];i;i=nex[i]){
if(to[i]!=fa&&!v[to[i]])dfs3(son,x,to[i],d+1);
}
}
int p1[18][100010],p2[18][100010],d2[100010];
void solve(int f,int x,int d){
int i;
n=0;
dfs1(0,x);
mn=inf;
dfs2(0,x);
fa[cn]=f;
d2[cn]=d;
dfs3(s1[cn],0,cn,0);
sort(s1[cn].begin(),s1[cn].end());
i=0;
for(it=s1[cn].begin();it!=s1[cn].end();it++)p1[d][it->x]=++i;
b1[cn].resize(n);
dfs3(s2[cn],0,x,0);
sort(s2[cn].begin(),s2[cn].end());
i=0;
for(it=s2[cn].begin();it!=s2[cn].end();it++)p2[d][it->x]=++i;
b2[cn].resize(n);
x=cn;
v[x]=1;
for(i=h[x];i;i=nex[i]){
if(!v[to[i]])solve(x,to[i],d+1);
}
}
#define pos(s,v) upper_bound(s[u].begin(),s[u].end(),pr(inf,v))-s[u].begin()
void modify(int x,int d,int w){
int u,l;
l=0;
for(u=x;fa[u];u=fa[u]){
if(d-l>=0)b1[u].add(1,pos(s1,d-l),w);
l=dis(fa[u],x);
if(d-l-1>=0)b2[u].add(1,pos(s2,d-l-1),-w);
}
if(d-l>=0)b1[u].add(1,pos(s1,d-l),w);
}
int query(int x){
int u,s=0;
for(u=x;fa[u];u=fa[u])s+=b2[u].query(p2[d2[u]][x])+b1[u].query(p1[d2[u]][x]);
s+=b1[u].query(p1[d2[u]][x]);
return s;
}
int main(){
int n,m,i,j,x,y,z;
char s[5];
scanf("%d%d",&n,&m);
for(i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
M=0;
dfs(0,1);
for(i=2;i<=M;i++)lg[i]=lg[i>>1]+1;
for(j=1;j<18;j++){
for(i=1;i+(1<<j)-1<=M;i++)f[i][j]=mind(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
solve(0,1,0);
while(m--){
scanf("%s%d",s,&x);
if(s[0]=='Q')
printf("%d\n",query(x));
else{
scanf("%d%d",&y,&z);
modify(x,y,z);
}
}
}