iinattr

点分树

2022-07-24

点分树是一种将点分治离线下来的算法

通过点分治将每一层的重心作为儿子链接到上一层的重心上

可以发现这样的一棵点分治重构树只有logn层

枚举点对的代价只有nlogn

而这棵树上任两点的lca必在两点原树路径上

所以可以使暴力算法在这上面达到nlogn

并且带修改题目往往只会修改点权而不会修改树形

所以可以支持带修

例题

P6329

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    #include<bits/stdc++.h>
using namespace std;
#define N 5000006
int head[N],nxt[N],to[N],cntt=0;
int val[N];
int root,n,m,size[N],vis[N],msize[N],tot;
int fa[N][20],dep[N];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
void dfs(register int x,register int f)
{
fa[x][0]=f;
for(register int i=head[x];i;i=nxt[i])
{
register int u=to[i];
if(u==f) continue;
dep[u]=dep[x]+1;dfs(u,x);
}
}
int lca(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = 17; ~i; i--)
if (dep[x] - (1 << i) >= dep[y]) x = fa[x][i];
if (x == y) return x;
for (int i = 17; ~i; i--)
if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
int getdis(register int u,register int v)
{
return dep[u]+dep[v]-(dep[lca(u,v)]<<1);
}
void findcent(register int x,register int f,register int tot)
{
size[x]=1,msize[x]=0;
for(register int i=head[x];i;i=nxt[i])
{
register int v=to[i];
if(v==f||vis[v]) continue;
findcent(v,x,tot);
msize[x]=max(msize[x],size[v]);
size[x]+=size[v];
}
msize[x]=max(msize[x],tot-size[x]);
if(msize[x]<msize[root]) root=x;
}
int dfa[N+5];
void divrt(register int x,register int tot)
{
vis[x]=1;
for(register int i=head[x];i;i=nxt[i])
{
register int v=to[i];
if(vis[v]) continue;
root=0;
register int sz=(size[v]<size[x])?size[x]:(tot-size[x]);
findcent(v,x,sz);
dfa[root]=x;
divrt(root,sz);
}
}
struct segtree
{
int rt[N],ncnt=0;
struct node
{
int ch[2],val;
}tr[N];
void change(register int &x,register int l,register int r,register int p,register int k)
{
if(!x) x=++ncnt;
if(l==r)
{
tr[x].val+=k;
return;
}
register int mid=(l+r)>>1;
if(p<=mid) change(tr[x].ch[0],l,mid,p,k);
else change(tr[x].ch[1],mid+1,r,p,k);
tr[x].val=tr[tr[x].ch[0]].val+tr[tr[x].ch[1]].val;
}
int query(register int x,register int l,register int r,register int ql,register int qr)
{
if(!x) return 0;
if(ql<=l&&r<=qr) return tr[x].val;
register int mid=(l+r)>>1;
register int ret=0;
if(ql<=mid) ret+=query(tr[x].ch[0],l,mid,ql,qr);
if(mid<qr) ret+=query(tr[x].ch[1],mid+1,r,ql,qr);
return ret;
}
}w1,w2;
void change(register int x,register int k)
{
register int cur=x;
while(cur)
{
w1.change(w1.rt[cur],0,n-1,getdis(cur,x),k);
if(dfa[cur]) w2.change(w2.rt[cur],0,n-1,getdis(dfa[cur],x),k);
cur=dfa[cur];
}
}
int query(register int x,register int k)
{
register int cur=x,pre=0,ret=0;
while(cur)
{
if(getdis(cur,x)>k)
{
pre=cur;
cur=dfa[cur];
continue;
}
ret+=w1.query(w1.rt[cur],0,n-1,0,k-getdis(cur,x));
if(pre) ret-=w2.query(w2.rt[pre],0,n-1,0,k-getdis(cur,x));
pre=cur;
cur=dfa[cur];
}
return ret;
}
int main()
{
n=read();m=read();
tot=n;
for(register int i=1;i<=n;i++)
val[i]=read();
for(register int i=1;i<=n-1;i++)
{
register int x,y;
x=read();y=read();
nxt[++cntt]=head[x];
head[x]=cntt;
to[cntt]=y;
nxt[++cntt]=head[y];
head[y]=cntt;
to[cntt]=x;
}
dfs(1,0);
for(register int i=1;i<=19;i++)
for(register int j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
root=0;
msize[0]=0x3fffffff;
findcent(1,0,n);
divrt(root,n);
for(register int i=1;i<=n;i++)
change(i,val[i]);
register int preans=0;
while(m--)
{
register int opt,x,y;
opt=read(),x=read(),y=read();
x^=preans;
y^=preans;
if(opt==0)
{
preans=query(x,y);
printf("%d\n",preans);
}
else
{
change(x,y-val[x]);
val[x]=y;
}
}
return 0;
}