树链剖分

  • 对于换根操作,分三种情况讨论
  • 如果当前根就是要修改的点,那就直接全局修改
  • 如果当前根在要修改的子树之外,那就直接修改这个子树
  • 否则,通过画图可以发现,u的子树就是全树去掉(u,root)路径上深度最浅的点的子树
#include <bits/stdc++.h>
using namespace std;
vector<int>a[100005];
int dfn[100005],d[100005],s[100005],z[100005],h[100005],f[100005][17],tot,n;
int w[100005],c[100005];
void dfs1(int n1)
{
	s[n1]=1;
	for(int i=0;i<a[n1].size();i++)
	{
		d[a[n1][i]]=d[n1]+1;
		f[a[n1][i]][0]=n1;
		dfs1(a[n1][i]);
		s[n1]+=s[a[n1][i]];
		if(s[z[n1]]<s[a[n1][i]])
		{
			z[n1]=a[n1][i];
		}
	}
}
void dfs2(int n1)
{
	dfn[n1]=++tot;
	w[tot]=c[n1];
	if(z[n1])
	{
		h[z[n1]]=h[n1];
		dfs2(z[n1]);
	}
	for(int i=0;i<a[n1].size();i++)
	{
		if(!dfn[a[n1][i]])
		{
			h[a[n1][i]]=a[n1][i];
			dfs2(a[n1][i]);
		}
	}
}
struct t1
{
	int l,r;
	long long v,bj;
	#define len(x) t[x].r-t[x].l+1
}t[400005];
void build(int p,int l,int r)
{
	t[p].l=l;
	t[p].r=r;
	t[p].bj=0;
	if(l==r)
	{
		t[p].v=w[l];
		return;
	}
	int mid=(l+r)>>1;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	t[p].v=t[p*2].v+t[p*2+1].v;
}
void spread(int p)
{
	t[p*2].bj+=t[p].bj;
	t[p*2+1].bj+=t[p].bj;
	t[p*2].v+=t[p].bj*(len(p*2));
	t[p*2+1].v+=t[p].bj*(len(p*2+1));
	t[p].bj=0;
}
void change(int p,int l,int r,int v)
{
	if(l<=t[p].l&&r>=t[p].r)
	{
		t[p].v+=(len(p))*(long long)v;
		t[p].bj+=v;
		return;
	}
	spread(p);
	int mid=(t[p].l+t[p].r)>>1;
	if(l<=mid)
	{
		change(p*2,l,r,v);
	}
	if(r>mid)
	{
		change(p*2+1,l,r,v);
	}
	t[p].v=t[p*2].v+t[p*2+1].v;
}
long long ask(int p,int l,int r)
{
	if(l<=t[p].l&&r>=t[p].r)
	{
		return t[p].v;
	}
	spread(p);
	int mid=(t[p].l+t[p].r)>>1;
	long long va=0;
	if(l<=mid)
	{
		va+=ask(p*2,l,r);
	}
	if(r>mid)
	{
		va+=ask(p*2+1,l,r);
	}
	return va;
}
void pre()
{
	for(int j=1;j<=16;j++)
	{
		for(int i=1;i<=n;i++)
		{
			f[i][j]=f[f[i][j-1]][j-1];
		}
	}
}
int get(int p,int q)
{
	for(int i=16;i>=0;i--)
	{
		if(d[f[p][i]]>d[q])
		{
			p=f[p][i];
		}
	}
	return p;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>c[i];
	}
	for(int i=2;i<=n;i++)
	{
		int fa;
		cin>>fa;
		a[fa].push_back(i);
	}
	d[1]=1;
	dfs1(1);
	dfs2(1);
	build(1,1,tot);
	pre();
	int m;
	cin>>m;
	int root=1;
	for(int i=1;i<=m;i++)
	{
		int opt,u,v,k;
		cin>>opt>>u;
		long long res=0;
		if(opt==1)
		{
			root=u;
		}
		else if(opt==2)
		{
			cin>>v>>k;
			while(h[u]!=h[v])
			{
				if(d[h[u]]<d[h[v]])
				{
					swap(u,v);
				}
				change(1,dfn[h[u]],dfn[u],k);
				u=f[h[u]][0];
			}
			change(1,min(dfn[u],dfn[v]),max(dfn[u],dfn[v]),k);
		}
		else if(opt==3)
		{
			cin>>k;
			if(dfn[root]>dfn[u]&&dfn[root]<=dfn[u]+s[u]-1)
			{
				change(1,1,tot,k);
				u=get(root,u);
				change(1,dfn[u],dfn[u]+s[u]-1,-k);
			}
			else if(root==u)
			{
				change(1,1,tot,k);
			}
			else
			{
				change(1,dfn[u],dfn[u]+s[u]-1,k);
			}
		}
		else if(opt==4)
		{
			cin>>v;
			while(h[u]!=h[v])
			{
				if(d[h[u]]<d[h[v]])
				{
					swap(u,v);
				}
				res+=ask(1,dfn[h[u]],dfn[u]);
				u=f[h[u]][0];
			}
			res+=ask(1,min(dfn[u],dfn[v]),max(dfn[u],dfn[v]));
			cout<<res<<"\n";
		}
		else
		{
			if(dfn[root]>dfn[u]&&dfn[root]<=dfn[u]+s[u]-1)
			{
				u=get(root,u);
				res=ask(1,1,tot)-ask(1,dfn[u],dfn[u]+s[u]-1);
			}
			else if(root==u)
			{
				res=ask(1,1,tot);
			}
			else
			{
				res=ask(1,dfn[u],dfn[u]+s[u]-1);
			}
			cout<<res<<"\n";
		}
	}
	return 0;
}
posted @ 2025-02-17 22:06  D06  阅读(8)  评论(0)    收藏  举报
//雪花飘落效果