HDU - 3966(树链剖分)

讲解:https://blog.csdn.net/qq_45458915/article/details/102993978

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5e4+10;
int h[N],e[N*2],ne[N*2],idx;
int n,m,p;
int a[N];
int c,size[N],depth[N],fa[N],in[N],ord[N],son[N],top[N];
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
void dfs1(int x,int f,int d)
{
	depth[x]=d;
	fa[x]=f;
	size[x]=1;
	son[x]=-1;
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==f) continue;
		dfs1(j,x,d+1);
		size[x]+=size[j]; 
		if(son[x]==-1||size[j]>size[son[x]])
		{
			son[x]=j;
		}
	}
	
}
void dfs2(int x,int f,int t)
{
	top[x]=t;
	in[x]=++c;
	ord[c]=x;
	if(son[x]!=-1)
	{
		dfs2(son[x],x,t);
	}
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==f||son[x]==j)
		{
			continue;
		}
		dfs2(j,x,j);
	}
}
struct node{
	int l,r,sum,lazy;
}t[N*4];
void up(int x)
{
	t[x].sum=t[x*2].sum+t[x*2+1].sum;
}
void down(int x)
{
	if(t[x].lazy!=0)
	{
		t[x*2].lazy+=t[x].lazy;
		t[x*2+1].lazy+=t[x].lazy;
		t[x*2].sum+=t[x].lazy*(t[x*2].r-t[x*2].l+1);
		t[x*2+1].sum+=t[x].lazy*(t[x*2+1].r-t[x*2+1].l+1);
		t[x].lazy=0;
	}
}
void build(int x,int l,int r)
{
	t[x].l=l;t[x].r=r;t[x].lazy=0;//lazy一定要在这里初始化 
	if(l==r)
	{
		t[x].sum=a[ord[l]];
		return;
	}
	int mid=(l+r)/2;
	build(x*2,l,mid);
	build(x*2+1,mid+1,r);
	up(x);
}
void change(int x,int a,int b,int k)
{
	if(t[x].l>=a&&t[x].r<=b)
	{
		t[x].lazy+=k;
		t[x].sum+=k*(t[x].r-t[x].l+1);
		return;
	}
	down(x);
	int mid=(t[x].l+t[x].r)/2;
	if(a<=mid) change(x*2,a,b,k);
	if(b>mid) change(x*2+1,a,b,k);
	up(x);
}
int query(int x,int a)
{
	if(t[x].l==t[x].r)
	{
		return t[x].sum;				
	}
	down(x);
	int mid=(t[x].l+t[x].r)/2;
	if(a<=mid) return query(x*2,a);
	else return query(x*2+1,a);
	
}
void solve(int a,int b,int c,int flag)
{
	while(top[a]!=top[b])
	{
		if(depth[top[a]]<depth[top[b]]) swap(a,b);
		if(flag==1) change(1,in[top[a]],in[a],c);
		else change(1,in[top[a]],in[a],-c);
		a=fa[top[a]];
	}
	if(depth[a]<depth[b]) swap(a,b);
	if(flag==1) change(1,in[b],in[a],c);
	else change(1,in[b],in[a],-c);
}
int main()
{
	while(scanf("%d%d%d",&n,&m,&p)!=EOF)
	{
		memset(h,-1,sizeof h);
		idx=0;c=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
		}
		for(int i=1;i<n;i++)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			add(a,b);add(b,a);
		}
		dfs1(1,-1,1);
		dfs2(1,-1,1);
		build(1,1,n);
		char s[2];
		while(p--)
		{
			scanf("%s",s);
			if(s[0]=='I')
			{
				int a,b,c;
				scanf("%d%d%d",&a,&b,&c);
				solve(a,b,c,1);
			}
			else if(s[0]=='D')
			{
				int a,b,c;
				scanf("%d%d%d",&a,&b,&c);
				solve(a,b,c,0);
			}
			else
			{
				int a;
				scanf("%d",&a);
				printf("%d\n",query(1,in[a]));
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值