两种操作:
1.查询与树上结点x距离不超过k的结点权值之和
2.将结点x的权值修改为y
点分树模板题。
首先考虑一种比较暴力的做法:用树形dp的思想,将树转化成有根树,设f[u][k]为结点u子树下与其距离不超过k的点权和,则ans(x,k)=f[u][k]+f[fa[u]][k-1]-f[u][k-2]+f[fa[fa[u]]][k-2]-f[fa[u]][k-3]...,可如果树太高的话就GG了,要是能把树高变成logn级别的就好了。
建立点分树(点分治过程中形成的树),每个结点维护两个树状数组,一个维护以该结点为重心的各个距离上的权值和,一个维护其虚父亲(点分树上的父亲)在“该结点方向”上的各个距离上的权值和(用于容斥)。还要另外维护一个数据结构用于求原树上两点之间距离(树剖效率比较高),修改和询问就从当前结点开始不断向上跳即可。(点分树的树高是logn级别的,可以暴力往上跳)
总复杂度$O(nlogn+qlog^2n)$
1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const int N=1e5+10,inf=0x3f3f3f3f;
5 struct E {int v,nxt;} e[N<<1];
6 int a[N],hd[N],ne,n,Q,siz[N],mx[N],vis[N],RT,tot,cnt[N],fa[N];
7 int buf[N*40],*ptr=buf;
8 struct BIT {
9 int *c,n;
10 int lb(int x) {return x&-x;}
11 void add(int u,int x) {for(; u<=n; u+=lb(u))c[u]+=x;}
12 int get(int u) {int ret=0; for(u=min(u,n); u; u-=lb(u))ret+=c[u]; return ret;}
13 void build(int* a) {
14 for(int i=1; i<=n; ++i)c[i]=a[i];
15 for(int i=1; i<=n; ++i)if(i+lb(i)<=n)c[i+lb(i)]+=c[i];
16 }
17 } c[N][2];
18 BIT newBIT(int n) {BIT t= {ptr,n}; ptr+=n+1; return t;}
19 struct LCA {
20 int fa[N],son[N],dep[N],siz[N],top[N];
21 void dfs1(int u,int f,int d) {
22 fa[u]=f,son[u]=0,dep[u]=d,siz[u]=1;
23 for(int i=hd[u]; ~i; i=e[i].nxt) {
24 int v=e[i].v;
25 if(v==fa[u])continue;
26 dfs1(v,u,d+1),siz[u]+=siz[v];
27 if(siz[v]>siz[son[u]])son[u]=v;
28 }
29 }
30 void dfs2(int u,int tp) {
31 top[u]=tp;
32 if(son[u])dfs2(son[u],tp);
33 for(int i=hd[u]; ~i; i=e[i].nxt) {
34 int v=e[i].v;
35 if(v==fa[u]||v==son[u])continue;
36 dfs2(v,v);
37 }
38 }
39 int lca(int u,int v) {
40 for(; top[u]!=top[v]; u=fa[top[u]])if(dep[top[u]]<dep[top[v]])swap(u,v);
41 return dep[u]<dep[v]?u:v;
42 }
43 int dis(int u,int v) {return dep[u]+dep[v]-2*dep[lca(u,v)];}
44 } lca;
45 void link(int u,int v) {e[ne]= (E) {v,hd[u]},hd[u]=ne++;}
46 void getrt(int u,int f) {
47 siz[u]=1,mx[u]=0;
48 for(int i=hd[u]; ~i; i=e[i].nxt) {
49 int v=e[i].v;
50 if(vis[v]||v==f)continue;
51 getrt(v,u),siz[u]+=siz[v],mx[u]=max(mx[u],siz[v]);
52 }
53 mx[u]=max(mx[u],tot-siz[u]);
54 if(mx[u]<mx[RT])RT=u;
55 }
56 void getdis(int u,int f,int d) {
57 cnt[d]+=a[u];
58 for(int i=hd[u]; ~i; i=e[i].nxt) {
59 int v=e[i].v;
60 if(vis[v]||v==f)continue;
61 getdis(v,u,d+1);
62 }
63 }
64 void cal(int u,int f) {
65 int m=1;
66 for(; cnt[m]; ++m);
67 --m;
68 c[u][f]=newBIT(m);
69 c[u][f].build(cnt);
70 for(int i=1; i<=m; ++i)cnt[i]=0;
71 }
72 void solve(int u) {
73 getdis(u,0,1),cal(u,0),vis[u]=1;
74 for(int i=hd[u]; ~i; i=e[i].nxt) {
75 int v=e[i].v;
76 if(vis[v])continue;
77 getdis(v,0,1),RT=0,tot=siz[v];
78 getrt(v,0),cal(RT,1),fa[RT]=u,solve(RT);
79 }
80 }
81 void upd(int u,int x) {
82 x-=a[u],a[u]+=x;
83 int dis=0;
84 c[u][0].add(dis+1,x);
85 for(int v=u; fa[v]; v=fa[v]) {
86 dis=lca.dis(u,fa[v]);
87 c[fa[v]][0].add(dis+1,x),c[v][1].add(dis,x);
88 }
89 }
90 int qry(int u,int d) {
91 int ret=0,dis=d;
92 ret+=c[u][0].get(dis+1);
93 for(int v=u; fa[v]; v=fa[v]) {
94 dis=d-lca.dis(u,fa[v]);
95 if(dis>=0)ret+=c[fa[v]][0].get(dis+1)-c[v][1].get(dis);
96 }
97 return ret;
98 }
99 int main() {
100 memset(hd,-1,sizeof hd),ne=0;
101 scanf("%d%d",&n,&Q);
102 for(int i=1; i<=n; ++i)scanf("%d",&a[i]);
103 for(int i=1; i<n; ++i) {
104 int u,v;
105 scanf("%d%d",&u,&v);
106 link(u,v);
107 link(v,u);
108 }
109 mx[0]=inf,RT=0,tot=n,getrt(1,0),fa[RT]=0,solve(RT);
110 lca.dfs1(1,0,1),lca.dfs2(1,1);
111 for(int la=0; Q--;) {
112 int f,u,x;
113 scanf("%d%d%d",&f,&u,&x);
114 u^=la,x^=la;
115 if(f==0)printf("%d\n",la=qry(u,x));
116 else upd(u,x);
117 }
118 return 0;
119 }
来源:https://www.cnblogs.com/asdfsag/p/12513986.html