LightOJ - 1348 Aladdin and the Return Journey(树链剖分)

本文介绍了一种基于树状结构的数据处理算法,通过构建树状数组实现节点权值的快速查询与更新。该算法适用于解决涉及树形结构中节点权值累加查询及单点更新的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给一个树和树上点的权值,两个操作

0 a b 查询a到b的权值和

1 a b 把点a修改为b

/*
题意:给一个树和树上点的权值,两个操作,
一个是将点的权值修改,一个是询问u到v的点权和
*/
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
#define maxn 300050

int dep[maxn],top[maxn],size[maxn],son[maxn],fa[maxn],id[maxn],val[maxn],val_pre[maxn];
int n,m,t,topw,num;

struct node{
	int u,v,next;
}e[maxn];
int head[maxn];

void add(int x,int y)
{
	e[num].u=x;e[num].v=y;e[num].next=head[x];head[x]=num++;
}

void dfs_1(int u,int f,int d)
{
	dep[u]=d;
	size[u]=1;
	son[u]=0;
	fa[u]=f;
	for(int i=head[u];~i;i=e[i].next)
	{
		int v=e[i].v;
		if(v==f)continue;
		dfs_1(v,u,d+1);
		size[u]+=size[v];
		if(size[son[u]]<size[v]) son[u]=v;
	}
}
void dfs_2(int u,int tp)
{
	top[u]=tp;
	id[u]=++topw;
	if(son[u]) dfs_2(son[u],tp);
	for(int i=head[u];~i;i=e[i].next)
	{
		int v=e[i].v;
		if(v==fa[u]||v==son[u]) continue;
		dfs_2(v,v);
	}
}

struct Tree{
	int l,r,val;
}tree[maxn<<2];
void push_up(int st)
{
	tree[st].val=tree[st<<1].val+tree[st<<1|1].val;
}
void build(int st,int l,int r)
{
	tree[st].l=l;tree[st].r=r;
	if(l==r)
	{
		tree[st].val=val[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(st<<1,l,mid);
	build(st<<1|1,mid+1,r);
	push_up(st);
}
int query(int L,int R,int st)
{
	int l=tree[st].l,r=tree[st].r;
	int mid=(l+r)>>1;
	if(L<=l&&R>=r)
	{
		return tree[st].val;
	}
	if(R<=mid) return query(L,R,st<<1);
	else if(L>mid) return query(L,R,st<<1|1);
	else return query(L,mid,st<<1)+query(mid+1,R,st<<1|1);
}

int change(int u,int v)
{
	int ans=0;
	int tp1=top[u],tp2=top[v];
	while(tp1!=tp2)
	{
		if(dep[tp1]<dep[tp2])
		{
			swap(u,v);swap(tp1,tp2);
		}
		ans+=query(id[tp1],id[u],1);
		u=fa[tp1];tp1=top[u];
	}
	if(dep[u]>dep[v])swap(u,v);
	ans+=query(id[u],id[v],1);
	return ans;
}
void update(int x,int y,int st)
{
	int l=tree[st].l,r=tree[st].r;
	if(l==r)
	{
		tree[st].val=y;return ;
	}
	int mid=(l+r)>>1;
	if(x<=mid) update(x,y,st<<1);
	else update(x,y,st<<1|1);
	push_up(st);
}
int main()
{
	int cas=1;
	scanf("%d",&t);
	while(t--)
	{
		num=0;topw=0;
		memset(head,-1,sizeof(head));
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&val_pre[i]);
		for(int i=1;i<n;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);x++;y++;
			add(x,y);
			add(y,x);
		}
		dfs_1(1,0,1);
		dfs_2(1,1);
		for(int i=1;i<=n;i++)
		{
			val[id[i]]=val_pre[i];
		}
		build(1,1,topw);
		scanf("%d",&m);
		printf("Case %d:\n",cas++);
		while(m--)
		{
			int q,x,y;
			scanf("%d%d%d",&q,&x,&y);
			if(q==0)
			{
				x++,y++;
				printf("%d\n",change(x,y));		//区间求和 
			}
			else
			{
				x++;
				update(id[x],y,1);				//单点修改 
			}
		}
	}
	return 0;
}
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值