LightOJ 1348 - Aladdin and the Return Journey 树链剖分 点权

1348 - Aladdin and the Return Journey
PDF (English) Statistics Forum
Time Limit: 2 second(s) Memory Limit: 32 MB

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 i to 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 n space separated integers between 0and 1000, denoting the number of genies in the nodes respectively. Then there are n-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 ito j.

Sample Input

Output for Sample Input

1

 

4

10 20 30 40

0 1

1 2

1 3

3

0 2 3

1 1 100

0 2 3

Case 1:

90

170

Note

Dataset is huge, use faster I/O methods.


题目链接:http://lightoj.com/volume_showproblem.php?problem=1348


输入n个点的值,再连成树的结构。  然后0 a b 计算a点到b点 的权值和, 1 a b  把点a的权值改成b。


#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=30000+10;
const int inf=9999999999;
struct Edge{
	int to,next;
};
struct Edge edge[maxn<<1];
int head[maxn],tot;
int stree[maxn];//节点v在线段树上的编号
int pre[maxn];//在线段树中编号为v节点所对应原图中的编号。
int fa[maxn];//f[v] 表示v的父亲节点
int son[maxn];//表示 与v同在一重链上的儿子节点(重儿子)
int num[maxn];//num[v] v为根的子树的节点数。
int top[maxn];//top[v] v所在链的顶端节点。
int deep[maxn];//deep[v] 表示v的深度(根的深度为1)
int data[maxn];

int pos,n;

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

void dfs1(int u,int father,int dep){
	int i;
	deep[u]=dep;
	fa[u]=father;
	num[u]=1;
	for(i=head[u];i!=-1;i=edge[i].next){
		int v=edge[i].to;
		if(v!=father){
			dfs1(v,u,dep+1);
			num[u]+=num[v];
			if(son[u]==-1 || num[v]>num[son[u]]){
				son[u]=v;
			}
		}
	}
}
//给点编号得到线段树上的对应标号
void getpos(int u,int sp){
	int i;
	top[u]=sp;
	stree[u]=pos++;
	pre[stree[u]]=u;
	if(son[u]==-1) return ;
	getpos(son[u],sp);
	for(i=head[u];i!=-1;i=edge[i].next){
		int v=edge[i].to;
		if(v!=son[u] && v!=fa[u]){
			getpos(v,v);
		}
	}
}
//树状数组or线段树or其他
int Max(int a,int b){
	if(a>b) return a;
	return b;
}

struct node{
	int l,r;
	int sum,max;
	int mid(){
		return (l+r)>>1;
	}
};
struct node tree[maxn<<2];

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

void build(int l,int r,int rt){
	tree[rt].l=l;
	tree[rt].r=r;
	if(l==r){
		tree[rt].sum=tree[rt].max=data[pre[l]];
		return ;
	}
	int m=tree[rt].mid();
	build(lson);
	build(rson);
	PushUp(rt);
}

void updata(int p,int add,int rt){
	if(tree[rt].l==tree[rt].r && tree[rt].l==p){
		tree[rt].sum=add;
		tree[rt].max=add;
		return ;
	}
	int m=tree[rt].mid();
	if(p<=m) updata(p,add,rt<<1);
	else updata(p,add,rt<<1|1);
	PushUp(rt);
}

int query_sum(int L,int R,int rt){
	if(L<=tree[rt].l && tree[rt].r<=R){
		return tree[rt].sum;
	}
	int m=tree[rt].mid();
	int ret=0;
	if(L<=m) ret+=query_sum(L,R,rt<<1);
	if(R>m) ret+=query_sum(L,R,rt<<1|1);
	PushUp(rt);
	return ret;
}

int query_max(int L,int R,int rt){
	if(L<=tree[rt].l && tree[rt].r<=R){
		return tree[rt].max;
	}
	int m=tree[rt].mid();
	int ret=-inf;
	if(L<=m) ret=max(ret,query_max(L,R,rt<<1));
	if(R>m) ret=max(ret,query_max(L,R,rt<<1|1));
	PushUp(rt);
	return ret;
}

int find_sum(int u,int v){
	int f1,f2,ans=0;
	f1=top[u];
	f2=top[v];
	while(f1!=f2){
		//始终f1的深度比f2要大。深度大先更新
		if(deep[f1]<deep[f2]){
			swap(f1,f2);
			swap(u,v);
		}
		ans+=query_sum(stree[f1],stree[u],1);
		u=fa[f1];
		f1=top[u];
	}
	if(deep[u]>deep[v])	ans+=query_sum(stree[v],stree[u],1);
	else ans+=query_sum(stree[u],stree[v],1);
	return ans;
}

int find_max(int u,int v){
	int f1,f2,ans=-inf;
	f1=top[u];
	f2=top[v];
	while(f1!=f2){
		//始终f1的深度比f2要大。深度大先更新
		if(deep[f1]<deep[f2]){
			swap(f1,f2);
			swap(u,v);
		}
		ans=max(ans,query_max(stree[f1],stree[u],1));
		u=fa[f1];
		f1=top[u];
	}
	if(deep[u]>deep[v]) ans=max(ans,query_max(stree[v],stree[u],1));
	else ans=max(ans,query_max(stree[u],stree[v],1));
	return ans;
}

void init(){
	tot=0;
	memset(head,-1,sizeof head);
	pos=1;
	memset(son,-1,sizeof son);
}

int main()
{ 
	int t;
	int cas=1;
	scanf("%d",&t);
	while(t--)
	{
		printf("Case %d:\n",cas++);
		int x,y;
		int q,i;
		init();
		scanf("%d",&n); 
		for(i=1;i<=n;i++){
			scanf("%d",&data[i]);
		}
		for(i=1;i<n;i++)
		{
			scanf("%d %d",&x,&y);
			x++;
			y++;
			addedge(x,y);
			addedge(y,x);
		} 

		dfs1(1,0,0);//根的deep是0.father从0开始。
		getpos(1,1);
		build(1,n,1);
		char op[10];
		scanf("%d",&q);
		while(q--){
			int a,b;
			scanf("%s",op);
			if(op[0]=='0'){
				scanf("%d %d",&a,&b); 
				a++,b++;
				printf("%d\n",find_sum(a,b)); 
			}
			else{
				scanf("%d %d",&a,&b);
				a++;
				updata(stree[a],b,1);
			}
		} 
	}
	return 0;
}

/*
4
10 20 30 40
0 1
1 2
1 3
3
0 2 3
1 1 100
0 2 3
*/




你可能感兴趣的:(树链剖分)