hdu 3966( 树链剖分+点权更新)

题意:给一棵树,并给定各个点权的值,然后有3种操作:

I C1 C2 K: 把C1与C2的路径上的所有点权值加上K

D C1 C2 K:把C1与C2的路径上的所有点权值减去K

Q C:查询节点编号为C的权值


解题思路:这道题是明显的树链剖分问题,只是这里是点权更新,注意与边权更新的不同,剩下的基本是模板了。


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 50010;
struct Segment
{
	int l,r,sum,lazy;
}tree[maxn<<2];
struct Edge
{
	int to,next;
}edge[maxn<<1];
int n,m,p,cnt,num,pre[maxn],A[maxn];
int top[maxn],son[maxn],size[maxn];
int fa[maxn],idx[maxn],dep[maxn];

void addedge(int u,int v)
{
	edge[cnt].to = v;
	edge[cnt].next = pre[u];
	pre[u] = cnt++;
}

void dfs(int u)
{
	size[u] = 1; son[u] = 0;
	int tmp = 0;
	for(int i = pre[u]; i != -1; i = edge[i].next)
	{
		int v = edge[i].to;
		if(fa[u] == v) continue;
		fa[v] = u;
		dep[v] = dep[u] + 1;
		dfs(v);
		size[u] += size[v];
		if(size[v] > tmp)
		{
			tmp = size[v];
			son[u] = v;
		}
	}
}

void build_tree(int u,int tp)
{
	idx[u] = ++num; top[u] = tp;
	if(son[u] != 0) build_tree(son[u],tp);
	for(int i = pre[u]; i != -1; i = edge[i].next)
	{
		int v = edge[i].to;
		if(fa[u] == v || son[u] == v) continue;
		build_tree(v,v);
	}
}

void build_Segment(int rt,int l,int r)
{
	tree[rt].l = l, tree[rt].r = r;
	tree[rt].sum = tree[rt].lazy = 0;
	if(l == r) return;
	int mid = (l + r) >> 1;
	build_Segment(rt<<1,l,mid);
	build_Segment(rt<<1|1,mid+1,r);
}

void PushDown(int rt)
{
	if(tree[rt].lazy != 0)
	{
		tree[rt<<1].lazy += tree[rt].lazy;
		tree[rt<<1].sum += tree[rt].lazy;
		tree[rt<<1|1].lazy += tree[rt].lazy;
		tree[rt<<1|1].sum += tree[rt].lazy;
		tree[rt].lazy = 0;
	}
}

void PushUp(int rt)
{
	tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void update(int rt,int l,int r,int val)
{
	if(l <= tree[rt].l && tree[rt].r <= r)
	{
		tree[rt].sum += val;
		tree[rt].lazy += val;
		return;
	}
	PushDown(rt);
	int mid = (tree[rt].l + tree[rt].r) >> 1;
	if(l <= mid) update(rt<<1,l,r,val);
	if(mid < r) update(rt<<1|1,l,r,val);
	PushUp(rt);
}

int query(int rt,int pos)
{
	if(tree[rt].l == tree[rt].r)
		return tree[rt].sum;
	PushDown(rt);
	int mid = (tree[rt].l + tree[rt].r) >> 1;
	if(pos <= mid) return query(rt<<1,pos);
	else return query(rt<<1|1,pos);
}

void Modify(int a,int b,int val)
{
	int f1 = top[a], f2 = top[b];
	while(f1 != f2)
	{
		if(dep[f1] < dep[f2])
		{
			swap(f1,f2);
			swap(a,b);
		}
		update(1,idx[f1],idx[a],val);
		a = fa[f1], f1 = top[a];
	}
	if(dep[a] > dep[b]) swap(a,b);
	update(1,idx[a],idx[b],val);
}

int main()
{
	int u,v,val;
	char op[2];
	while(scanf("%d%d%d",&n,&m,&p)!=EOF)
	{
		memset(pre,-1,sizeof(pre));
		cnt = num = 0;
		dep[1] = 0;
		for(int i = 1; i <= n; i++)
			scanf("%d",&A[i]);
		for(int i = 1; i <= m; i++)
		{
			scanf("%d%d",&u,&v);
			addedge(u,v);
			addedge(v,u);
		}
		dfs(1);
		build_tree(1,1);
		build_Segment(1,1,num);
		for(int i = 1; i <= n; i++)
			update(1,idx[i],idx[i],A[i]);
		while(p--)
		{
			getchar();
			scanf("%s",op);
			if(op[0] == 'I')
			{
				scanf("%d%d%d",&u,&v,&val);
				Modify(u,v,val);
			}
			else if(op[0] == 'D')
			{
				scanf("%d%d%d",&u,&v,&val);
				Modify(u,v,-val);
			}
			else
			{
				scanf("%d",&u);
				printf("%d\n",query(1,idx[u]));
			}
		}
	}
	return 0;
}


你可能感兴趣的:(LCA)