当前位置: 首页 > 工具软件 > Aladdin lamp > 使用案例 >

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

谢华彩
2023-12-01
思路:一道树链剖分的基本题,给定一个数,节点数为n。先输入一个n,代表节点数,然后一行有n个数,代表 树上点从0 到n - 1的初始点权,然后n - 1行,每行两个数a b,代表这两个点之间有一条边。紧接着输入一个m,代表有m个操作,操作有两种:0 a b询问点a到点b路径上的点的权值和,1 a b把点a的权值更新为b


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
const int maxn = 30000+50;
int val[maxn],temp[maxn];
int siz[maxn],son[maxn],fa[maxn],id[maxn],dep[maxn],top[maxn];
int tot;
vector<int>e[maxn];
struct Tree
{
	int l,r;
	int sum;
}tree[maxn*4];
void push_up(int i)
{
	tree[i].sum = tree[i*2].sum+tree[i*2+1].sum;
}

void build(int i,int l,int r)
{
	tree[i].l=l;
	tree[i].r=r;
	if(l==r)
	{
		tree[i].sum = val[l];
		return;
	}
	int m = (l+r)>>1;
	build(i*2,l,m);
	build(i*2+1,m+1,r);
	push_up(i);
}
void update(int i,int v,int vall)
{
     if(tree[i].l==tree[i].r)
	 {
		 tree[i].sum=vall;
		 return;
	 }
	 int m = (tree[i].l+tree[i].r)>>1;
	 if(v<=m)
		 update(i*2,v,vall);
	 else
		 update(i*2+1,v,vall);
	 push_up(i);
}

int query(int i,int l,int r)
{
	if(tree[i].l>=l && tree[i].r <=r)
		return tree[i].sum;
	int m = (tree[i].l+tree[i].r)>>1;
	int ans = 0;
	if(l<=m)
		ans+=query(i*2,l,r);
	if(r>m)
		ans+=query(i*2+1,l,r);
	return ans;
}
void dfs1(int u,int f,int d)
{
	siz[u]=1;
	son[u]=0;
	dep[u]=d;
	fa[u]=f;
	for(int i = 0;i<e[u].size();i++)
	{
		int v = e[u][i];
		if(v==f)
			continue;
		dfs1(v,u,d+1);
		siz[u]+=siz[v];
		if(siz[son[u]]<siz[v])
			son[u]=v;
	}
}
void dfs2(int u,int tp)
{
     top[u]=tp;
	 id[u]=++tot;
	 if(son[u])
		 dfs2(son[u],tp);
	 for(int i = 0;i<e[u].size();i++)
	 {
		 int v = e[u][i];
		 if(v==fa[u]||v==son[u])
			 continue;
		 dfs2(v,v);
	 }
}
int Yough(int u,int v)
{
	int tp1 = top[u],tp2 = top[v];
	int ans = 0;
	while(tp1!=tp2)
	{
		if (dep[tp1]<dep[tp2])
		{
			swap(tp1,tp2);
			swap(u,v);
		}
		ans += query(1,id[tp1],id[u]);
	    u = fa[tp1];
		tp1 = top[u];
	}

	if (dep[u]>dep[v])
		swap(u,v);
	ans+=query(1,id[u],id[v]);
	return ans;
}

int main()
{
	int T,cas=1;
	scanf("%d",&T);
	while(T--)
	{
		printf("Case %d:\n",cas++);
		tot=0;
        int n;
		scanf("%d",&n);
		for(int i = 1;i<=n;i++)
		{
			e[i].clear();
			scanf("%d",&temp[i]);
		}
		for(int i = 1;i<n;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			u++,v++;
			e[u].push_back(v);
			e[v].push_back(u);
		}
        dfs1(1,0,1);
		dfs2(1,1);
		for(int i = 1;i<=n;i++)
			val[id[i]] = temp[i];
		build(1,1,tot);
		int q;
		scanf("%d",&q);
		while(q--)
		{
             int a,b,c;
			 scanf("%d",&a);
			 if(a==0)
			 {
                scanf("%d%d",&b,&c);
				b++,c++;
				printf("%d\n",Yough(b,c));
			 }
			 else if (a==1)
			 {
                scanf("%d%d",&b,&c);
				b++;
				update(1,id[b],c);
			 }
		}
	}
}


Description

Finally the Great Magical Lamp was in Aladdin's hand. Now he wanted to return home. But he didn't want to take any help from the Genie because he thought that it might be another adventure for him. All he remembered was the paths he had taken to reach there. But since he took the lamp, all the genies in the cave became angry and they were planning to attack. As Aladdin was not afraid, he wondered how many genies were there. He summoned the Genie from the lamp and asked this.

Now you are given a similar problem. For simplicity assume that, you are given a tree (a connected graph with no cycles) with n nodes, nodes represent places, edges represent roads. In each node, initially there are an arbitrary number of genies. But the numbers of genies change in time. So, you are given a tree, the number of genies in each node and several queries of two types. They are:

1)      0 i j, it means that you have to find the total number of genies in the nodes that occur in path from node ito j (0 ≤ i, j < n).

2)      1 i v, it means that number of genies in node i is changed to v (0 ≤ i < n, 0 ≤ v ≤ 1000).

Input

Input starts with an integer T (≤ 10), denoting the number of test cases.

Each case starts with a blank line. Next line contains an integer n (2 ≤ n ≤ 30000). The next line contains nspace separated integers between 0 and 1000, denoting the number of genies in the nodes respectively. Then there aren-1 lines each containing two integers: u v (0 ≤ u, v < n, u ≠ v) meaning that there is an edge from node u and v. Assume that the edges form a valid tree. Next line contains an integer q (1 ≤ q ≤ 105) followed by q lines each containing a query as described above.

Output

For each case, print the case number in a single line. Then for each query 0 i j, print the total number of genies in the nodes that occur in path i to j.

Sample Input

1

 

4

10 20 30 40

0 1

1 2

1 3

3

0 2 3

1 1 100

0 2 3

Sample Output

Case 1:

90

170



 类似资料: