P6329 【模板】点分树 | 震波
【题意】
给一个树,要求你支持如下操作
1.修改某个点的点权 2.询问到某个点的距离小于等于k的点权和
【分析】
首先看到这种树上距离相关的操作不难想到需要用点分治,由于其需要支持修改操作,所以我们要用到动态点分治并配合数据结构来维护
具体地,我们先建立点分树,对于树上的每个节点,维护2个树状数组,分别记录到子树内到当前距离为i的点权和、子树内到fa的距离为i的点权和
每次修改维护以上两个值,在查询的时候,我们先计算到询问点u距离为k的点权和,然后再向上计算到fa距离为k-dis(u,fa)的点权和,减去重复的部分,如此直到算到根节点结束即可
注意一个小细节,树状数组不能全开满,要根据子树内节点个数动态开点
【代码】
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; int n,m; int head[maxn],tot,v[maxn]; struct edge { int to,nxt; }e[maxn<<1]; void add(int x,int y) { e[++tot].to=y; e[tot].nxt=head[x]; head[x]=tot; } int vis[maxn],dfsfa[maxn],size,gsiz,siz[maxn],root; int dep[maxn],st[maxn][20],val[maxn]; void dfs(int u,int fa) { dep[u]=dep[fa]+1; st[u][0]=fa; for(int i=1;i<=18;i++) st[u][i]=st[st[u][i-1]][i-1]; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa) continue; dfs(to,u); } } int cnt,p[maxn]; void findrt(int u,int fa) { siz[u]=1; p[++cnt]=u; int maxsiz=0; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa || vis[to]) continue; findrt(to,u); siz[u]+=siz[to]; maxsiz=max(maxsiz,siz[to]); } maxsiz=max(maxsiz,size-siz[u]); if(maxsiz<gsiz) { gsiz=maxsiz; root=u; } } int lowbit(int x) { return x&(-x); } struct seg { vector <int> c; void build(int len) { for(int i=0;i<=len+2;i++) c.push_back(0); } void add(int x,int y) { for(int i=x;i<c.size();i+=lowbit(i)) c[i]+=y; } int query(int x) { int res=0; x=min(x,(int)c.size()-1); for(int i=x;i;i-=lowbit(i)) res+=c[i]; return res; } }S1[maxn],S2[maxn]; int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int i=18;i>=0;i--) if(dep[st[x][i]]>=dep[y]) x=st[x][i]; if(x==y) return x; for(int i=18;i>=0;i--) if(st[x][i]!=st[y][i]) x=st[x][i],y=st[y][i]; return st[x][0]; } int getdis(int x,int y) { return dep[x]+dep[y]-2*dep[lca(x,y)]; } void getpath(int rt,int u,int fa,int len) { S1[rt].add(len,val[u]); for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa || vis[to]) continue; getpath(rt,to,u,len+1); } } void solve(int u,int fa) { vis[u]=1; dfsfa[u]=fa; S2[u].build(cnt); if(fa) for(int i=1;i<=cnt;i++) S2[u].add(getdis(p[i],fa),val[p[i]]); S1[u].build(cnt); for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(vis[to]) continue; getpath(u,to,u,1); } for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(vis[to]) continue; gsiz=size=siz[to]; root=0; cnt=0; findrt(to,0); solve(root,u); } } int query(int x,int k) { int res=0,u=x; res+=S1[x].query(k)+val[x]; while(dfsfa[u]) { int d=getdis(x,dfsfa[u]); if(d<=k) res+=val[dfsfa[u]]+S1[dfsfa[u]].query(k-d)-S2[u].query(k-d); u=dfsfa[u]; } return res; } void update(int x,int y) { int u=x; while(dfsfa[u]) { int d=getdis(x,dfsfa[u]); S2[u].add(d,-val[x]); S2[u].add(d,y); u=dfsfa[u]; S1[u].add(d,-val[x]); S1[u].add(d,y); } val[x]=y; } int main() { scanf("%d%d",&n,&m); int x,y; for(int i=1;i<=n;i++) scanf("%d",&val[i]); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); size=gsiz=n; cnt=0; findrt(1,0); solve(root,0); int ans=0; for(int i=1;i<=m;i++) { int op; scanf("%d%d%d",&op,&x,&y); x^=ans; y^=ans; if(!op) printf("%d\n",ans=query(x,y)); else update(x,y); } return 0; }

浙公网安备 33010602011771号