点分治学习笔记

点分治就是在树上拿点分治

但是只能按照某个点对一个子树进行处理,所以一般处理路径问题

主要是找到重心,然后一直向下递归

找中心有个比较吊的写法,直接拿上一次这个点得到的大小作为子树大小求重心,正确性不会证明,直接用吧。

贴个代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,ma[10005],siz[10005],sum,q[10005],t[10000005],ans[10005],rt;
vector<pair<int,int>> e[10005];
bool vis[10005];
void getroot(int p,int fa){
	siz[p]=1;ma[p]=0;
	for(auto tmp:e[p]){
		int i=tmp.first;
		if(i==fa||vis[i])continue;
		getroot(i,p);
		siz[p]+=siz[i];
		ma[p]=max(ma[p],siz[i]);
	}
	ma[p]=max(ma[p],sum-siz[p]);
	if(ma[p]<ma[rt])rt=p;
}
void dfs(int p,int fa,int dis,int op){
	if(dis>1e7)return;
	if(!op){
		for(int i=1;i<=m;i++)if(dis<=q[i])ans[i]+=t[q[i]-dis];
	}
	else t[dis]+=op;
	for(auto tmp:e[p]){
		int i=tmp.first,w=tmp.second;
		if(i==fa||vis[i])continue;
		dfs(i,p,dis+w,op);
	}
}
void dfs0(int p){
	vis[p]=t[0]=1;
	for(auto tmp:e[p]){
		int i=tmp.first,w=tmp.second;
		if(vis[i])continue;
		dfs(i,0,w,0);
		dfs(i,0,w,1);
	}
	for(auto tmp:e[p]){
		int i=tmp.first,w=tmp.second;
		if(vis[i])continue;
		dfs(i,0,w,-1);
	}
	for(auto tmp:e[p]){
		int i=tmp.first,w=tmp.second;
		if(vis[i])continue;
		sum=siz[i];
		rt=0;
		getroot(i,p);
		dfs0(rt);
	}
}
signed main(){
	cin>>n>>m;
	for(int i=1,u,v,w;i<n;i++){
		cin>>u>>v>>w;
		e[u].push_back({v,w});
		e[v].push_back({u,w});
	}
	for(int i=1;i<=m;i++)cin>>q[i];
	ma[0]=sum=n;
	getroot(1,0);
	dfs0(rt);
	for(int i=1;i<=m;i++){
		if(ans[i])puts("AYE");
		else puts("NAY");
	}
	return 0;
}

然后是点分树

就是按照点分治的顺序遍历,然后直接就能按照树高进行修改操作了

然后可以在每个点存下所有子孙,比较方便

经典的记录这个子树给父亲的贡献搞一手容斥,点分树基本套路,一般都需要容↗斥↘技↘巧~

然后一般就解决了

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,a[100005],dep[100005],st[100005][18],rt,sum,ma[100005],siz[100005],pre[100005],siz2[100005];
bool vis[100005];
vector<int> e[100005];
vector<int> c[2][100005];
void pre_dfs(int p,int fa){
	dep[p]=dep[fa]+1;
	st[p][0]=fa;
	for(int i=1;i<18;i++)st[p][i]=st[st[p][i-1]][i-1];
	for(int i:e[p]){
		if(i==fa)continue;
		pre_dfs(i,p);
	}
}
int LCA(int l,int r){
	if(dep[l]<dep[r])swap(l,r);
	for(int i=17;i>=0;i--)if(dep[st[l][i]]>=dep[r])l=st[l][i];
	if(l==r)return l;
	for(int i=17;i>=0;i--){
		if(st[l][i]!=st[r][i]){
			l=st[l][i];
			r=st[r][i];
		}
	}
	return st[l][0];
}
int get_dis(int u,int v){
	return dep[u]+dep[v]-2*dep[LCA(u,v)];
}
void maxx(int &x,int y){
	x=x>y?x:y;
}
void getroot(int p,int fa){
	siz[p]=1,ma[p]=0;
	for(int i:e[p]){
		if(i!=fa&&!vis[i]){
			getroot(i,p);
			siz[p]+=siz[i];
			ma[p]=max(ma[p],siz[i]);
		}
	}
	ma[p]=max(ma[p],sum-siz[p]);
	if(ma[p]<ma[rt])rt=p;
}
void build_dfs(int p){
	vis[p]=1;
	siz2[p]=sum+1;
	c[0][p].resize(siz2[p]+1);
	c[1][p].resize(siz2[p]+1);
	for(int i:e[p]){
		if(!vis[i]){
			rt=0,sum=siz[i];
			getroot(i,0);
			pre[rt]=p;
			build_dfs(rt);
		}
	}
	
}
int lowbit(int x){
	return x&-x;
}
void add(int u,int op,int x,int v){
	x++;
	for(int i=x;i<=siz2[u];i+=lowbit(i))c[op][u][i]+=v;
}
int query(int u,int op,int x){
	x++;
	int res=0;
	x=min(x,siz2[u]);
	for(int i=x;i;i-=lowbit(i))res+=c[op][u][i];
	return res;
}
void change(int p,int v){
	for(int i=p;i;i=pre[i])add(i,0,get_dis(p,i),v);
	for(int i=p;pre[i];i=pre[i])add(i,1,get_dis(p,pre[i]),v);
}
int ask(int x,int y){
	int ans=query(x,0,y);
	for(int i=x;pre[i];i=pre[i]){
		int dis=get_dis(x,pre[i]);
		if(y>=dis)ans+=query(pre[i],0,y-dis)-query(i,1,y-dis);
	}
	return ans;
}
int read(){
	char c=getchar();
	int x=0;
	while(c>'9'||c<'0')c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x;
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1,u,v;i<n;i++){
		u=read(),v=read();
		e[u].push_back(v);
		e[v].push_back(u);
	}
	pre_dfs(1,0);
	ma[0]=sum=n,rt=0;
	getroot(1,0);
	build_dfs(rt);
	for(int i=1;i<=n;i++)change(i,a[i]);
	int la=0;
	for(int i=1,op,x,y;i<=m;i++){
		op=read(),x=read(),y=read();
		x^=la,y^=la;
		if(!op)la=ask(x,y),printf("%d\n",la);
		else change(x,y-a[x]),a[x]=y;
	}
	return 0;
}
posted @ 2025-11-28 09:36  huhangqi  阅读(0)  评论(0)    收藏  举报
/*
*/