LGP6329 [LG TPLT] 点分治·II 学习笔记
LGP6329 [LG TPLT] 点分治·II 学习笔记
题意简述
\(n\) 个结点的树,边有边权,\(m\) 次操作:
0 u k输出所有与 \(u\) 距离不大于 \(k\) 的点的权值和。1 u k单点修改,\(v_u=k\)。
强制在线。
做法解析
树形态是不变的。你不希望每次询问都重复一遍把递归下去的过程,所以你考虑建出一棵点分树。点分树就是沿递归子问题的结点连边所得。好点分树讲完了。
呃等下,回到这个问题本身,这个权值和怎么求解呢?
所有与 \(u\) 距离不超过 \(k\) 的权值和?在点分树上?因为我们知道点分树深度为 \(O(\log n)\),所以我们可以考虑直接暴力跳:对于点分树上从 \(u\) 开始往祖先的直链上的每一个点 \(v\),设 \(\text{dis}(u,v)=d\),则我们每次就把答案加上 \(v\) 点分树子树里距离 \(v\) 不超过 \(k-d\) 的点。
但是这会算重。为了去重,对于每一对直链上的父子 \((i,j)\),我们在加上 \(i\) 子树里距自己不超过 \(k-d\) 的点权值和的同时,还要减去 \(j\) 子树里距 \(i\) 不超过 \(k-d\) 的点权值和。
然后用树状数组就行。因为这是点分树,所以你对于每个结点开 \(siz\) 大小的空间可以接受。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e5+5;
int N,M,A[MaxN],X,Y,Opt;
vector<int> Tr[MaxN],Dr[MaxN];
void addudge(int u,int v){
Tr[u].push_back(v);
Tr[v].push_back(u);
}
int dep[MaxN],siz1[MaxN],tfa[MaxN],hvs[MaxN];
void dfs1(int u,int f){
dep[u]=dep[f]+1,siz1[u]=1,tfa[u]=f;
for(int v : Tr[u]){
if(v==f)continue;
dfs1(v,u),siz1[u]+=siz1[v];
if(siz1[v]>siz1[hvs[u]])hvs[u]=v;
}
}
int top[MaxN];
void dfs2(int u,int t){
top[u]=t;if(hvs[u])dfs2(hvs[u],t);
for(int v : Tr[u])if(v!=tfa[u]&&v!=hvs[u])dfs2(v,v);
}
int getlca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=tfa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int getdis(int x,int y){return dep[x]+dep[y]-2*dep[getlca(x,y)];}
int siz2[MaxN],hsw[MaxN],vis[MaxN];
int getroot(int u,int f,int tot){
siz2[u]=1,hsw[u]=0;int t=0,x;
for(int v : Tr[u]){
if(v==f||vis[v])continue;
x=getroot(v,u,tot);if(hsw[x]<hsw[t])t=x;
siz2[u]+=siz2[v],maxxer(hsw[u],siz2[v]);
}
maxxer(hsw[u],tot-siz2[u]);
if(hsw[u]<hsw[t])t=u;
return t;
}
struct BinidTree{
int n;vector<int> t;
int lowbit(int x){return x&(-x);}
void init(int x){t.clear(),n=x,t.resize(n+1);}
void add(int p,int x){p++;for(;p<=n;p+=lowbit(p))t[p]+=x;}
int gts(int p){
p++,minner(p,n);int res=0;
for(;p;res+=t[p],p-=lowbit(p));return res;
}
}BiT[MaxN][2];
int dfa[MaxN];
void build(int u,int s,int utot){
vis[u]=1;
BiT[u][0].init(utot+1);
BiT[u][1].init(utot+1);
for(int v : Tr[u]){
if(vis[v])continue;
int vtot=siz2[v]<siz2[u]?siz2[v]:siz2[s]-siz2[u];
int rt=getroot(v,0,vtot);dfa[rt]=u,build(rt,v,vtot);
}
}
void abuild(){hsw[0]=N,build(getroot(1,0,N),1,N);}
void modify(int u,int w){
for(int i=u;i;i=dfa[i])BiT[i][0].add(getdis(u,i),w);
for(int i=u;dfa[i];i=dfa[i])BiT[i][1].add(getdis(u,dfa[i]),w);
}
int ans;
int acount(int u,int k){
int res=BiT[u][0].gts(k);
for(int i=u;dfa[i];i=dfa[i]){
int tdis=k-getdis(u,dfa[i]);
if(tdis>=0)res+=BiT[dfa[i]][0].gts(tdis)-BiT[i][1].gts(tdis);
}
return res;
}
void aupdate(int u,int k){modify(u,k-A[u]),A[u]=k;}
int main(){
readis(N,M);
for(int i=1;i<=N;i++)readi(A[i]);
for(int i=1;i<N;i++)readis(X,Y),addudge(X,Y);
dfs1(1,0),dfs2(1,1);abuild();
for(int i=1;i<=N;i++)modify(i,A[i]);
for(int i=1;i<=M;i++){
readis(Opt,X,Y);
X^=ans,Y^=ans;
if(Opt==0)ans=acount(X,Y),writil(ans);
if(Opt==1)aupdate(X,Y);
}
return 0;
}
浙公网安备 33010602011771号