题意
给定N个点的一棵边权都为1的树,每个点有点权 。M次操作,两种类型
1.单点点权修改。
2.给出x和k,询问到x的距离不超过K的所有点权和。
操作加密,强制在线。
N,M<=100000
题解
动态点分治。
同样把信息收集到根。对于每个点分树,把所有点放到一个树状数组中,数状数组的下标即是到根的距离。要注意相同子树中的东西计算重复了,为了抠去重复部分,还需要对每个点分树再开一个数状数组,维护其中的点到父点分树的根的距离。这样修改和询问都是暴力爬树高,修改时在途中进行树状数组的单点修改,询问的话每次统计一下经过当前根的路径对应的权值和即可。
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=100005, maxe=200005;
int n,m,w[maxn],last_print;
int fir[maxn],nxt[maxe],son[maxe],tot;
bool vis[maxn];
int sz[maxn];
//------------------------------------------------------------------------
int rt,allmin,allsz,MaxD,d[maxn];
int dfs_info(int x,int fa){
sz[x]=1;
for(int j=fir[x];j;j=nxt[j]) if(son[j]!=fa&&!vis[son[j]]){
d[son[j]]=d[x]+1; MaxD=max(MaxD,d[son[j]]);
dfs_info(son[j],x); sz[x]+=sz[son[j]];
}
}
void dfs_G(int x,int fa){
int _max=0;
for(int j=fir[x];j;j=nxt[j]) if(son[j]!=fa&&!vis[son[j]]){
dfs_G(son[j],x);
_max=max(_max,sz[son[j]]);
}
if(allmin>max(_max,allsz-sz[x])) allmin=max(_max,allsz-sz[x]), rt=x;
}
int find_G(int x){
allmin=1e+9;
MaxD=d[x]=0; dfs_info(x,0); allsz=sz[x];
dfs_G(x,0);
return rt;
}
//------------------------------------------------------------------------
int dep[maxn],anc[maxn][25];
void dfs_LCA(int x,int fa){
anc[x][0]=fa;
for(int j=1;j<=20;j++) anc[x][j]=anc[anc[x][j-1]][j-1];
for(int j=fir[x];j;j=nxt[j]) if(son[j]!=fa)
dep[son[j]]=dep[x]+1, dfs_LCA(son[j],x);
}
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int j=20;j>=0;j--) if(dep[anc[x][j]]>=dep[y]) x=anc[x][j];
if(x==y) return x;
for(int j=20;j>=0;j--) if(anc[x][j]!=anc[y][j]) x=anc[x][j], y=anc[y][j];
return anc[x][0];
}
int getDis(int x,int y){
return dep[x]+dep[y]-dep[LCA(x,y)]*2;
}
//------------------------------------------------------------------------
vector< int > bit[maxn][2];
void bit_Updata(int k1,int k2,int x,int val){
int len=bit[k1][k2].size()-1;
for(x++;x<=len;x+=(x&(-x))) bit[k1][k2][x]+=val;
}
int bit_Query(int k1,int k2,int x){
int res=0, len=bit[k1][k2].size()-1;
for(x=min(x+1,len);x;x-=(x&(-x))) res+=bit[k1][k2][x];
return res;
}
//------------------------------------------------------------------------
int prt[maxn];
void dfs_push(int x,int fa,int id){
bit_Updata(id,0,getDis(x,id),w[x]);
if(prt[id]) bit_Updata(id,1,getDis(x,prt[id]),w[x]);
for(int j=fir[x];j;j=nxt[j]) if(son[j]!=fa&&!vis[son[j]]) dfs_push(son[j],x,id);
}
void DivTree(int x,int faG){
int G=find_G(x);
prt[G]=faG; vis[G]=true;
bit[G][0].resize(allsz+3); bit[G][1].resize(allsz+3);
dfs_push(G,0,G);
for(int j=fir[G];j;j=nxt[j]) if(!vis[son[j]]) DivTree(son[j],G);
}
void Updata(int x,int val){
for(int y=x;y;y=prt[y]){
bit_Updata(y,0,getDis(x,y),val-w[x]);
if(prt[y]) bit_Updata(y,1,getDis(x,prt[y]),val-w[x]);
}
}
int Query(int x,int K){
int res=bit_Query(x,0,K);
for(int y=x;prt[y];y=prt[y]) if(K>=getDis(x,prt[y]))
res+=bit_Query(prt[y],0,K-getDis(x,prt[y]))-bit_Query(y,1,K-getDis(x,prt[y]));
return res;
}
//------------------------------------------------------------------------
void add(int x,int y){
son[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot;
}
int getint(){
int res=0; char ch=getchar();
while(!('0'<=ch&&ch<='9')) ch=getchar();
while('0'<=ch&&ch<='9') res=res*10+ch-'0', ch=getchar();
return res;
}
int main(){
freopen("bzoj3730.in","r",stdin);
freopen("bzoj3730.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) w[i]=getint();
for(int i=1;i<=n-1;i++){
int x=getint(),y=getint();
add(x,y); add(y,x);
}
dfs_LCA(1,0);
DivTree(1,0);
while(m--){
int pd=getint(),x=getint(),y=getint();
x^=last_print; y^=last_print;
if(!pd) printf("%d\n",last_print=Query(x,y));
else Updata(x,y), w[x]=y;
}
return 0;
}