1. 程式人生 > >P2590 [ZJOI2008]樹的統計

P2590 [ZJOI2008]樹的統計

edge 一個點 i++ 沒有 out 輸出 ins chang 更改

題目描述

一棵樹上有n個節點,編號分別為1到n,每個節點都有一個權值w。

我們將以下面的形式來要求你對這棵樹完成一些操作:

I. CHANGE u t : 把結點u的權值改為t

II. QMAX u v: 詢問從點u到點v的路徑上的節點的最大權值

III. QSUM u v: 詢問從點u到點v的路徑上的節點的權值和

註意:從點u到點v的路徑上的節點包括u和v本身

輸入輸出格式

輸入格式:

輸入文件的第一行為一個整數n,表示節點的個數。

接下來n – 1行,每行2個整數a和b,表示節點a和節點b之間有一條邊相連。

接下來一行n個整數,第i個整數wi表示節點i的權值。

接下來1行,為一個整數q,表示操作的總數。

接下來q行,每行一個操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式給出。

輸出格式:

對於每個“QMAX”或者“QSUM”的操作,每行輸出一個整數表示要求輸出的結果。

輸入輸出樣例

輸入樣例#1:
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
輸出樣例#1:
4
1
2
2
10
6
5
6
5
16

說明

對於100%的數據,保證1<=n<=30000,0<=q<=200000;中途操作中保證每個節點的權值w在-30000到30000之間。

裸的樹鏈剖分。

註意所有的值都要取最大或者最小。

有很小的負邊權!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ls k<<1
#define rs k<<1|1
using namespace std;
const int MAXN=1000001;
inline void read(int &n)
{
	char c=‘+‘;int x=0;bool flag=0;
	while(c<‘0‘||c>‘9‘)
	{c=getchar();if(c==‘-‘)flag=1;}
	while(c>=‘0‘&&c<=‘9‘)
	{x=(x<<1)+(x<<3)+c-48,c=getchar();}
	flag==1?n=-x:n=x;
}
int n;
int a[MAXN];
int fa[MAXN];// 每一個節點的父親節點
int deep[MAXN];// 每一個節點的深度
int top[MAXN];// 重鏈上的頂節點
int son[MAXN];// 每一個點的重兒子 
int size[MAXN];// 子節點的數量
int pos[MAXN];// 劃分輕重鏈之後的編號
int tot;// 總結點的數量 
struct node
{
	int l,r,maxn,sum;
}tree[MAXN];
struct EDGE
{
	int u,v,nxt;
}edge[MAXN];
int head[MAXN];
int num=1;
//int nowmax=-1;
int nowsum=0;
void update(int k)
{
	tree[k].maxn=max(tree[ls].maxn,tree[rs].maxn);
	tree[k].sum=(tree[ls].sum+tree[rs].sum);
}
void add_edge(int x,int y)
{
	edge[num].u=x;
	edge[num].v=y;
	edge[num].nxt=head[x];
	head[x]=num++;
}
int dfs1(int now,int nowfa,int nowdeep)
{
	deep[now]=nowdeep;
	fa[now]=nowfa;
	size[now]=1;
	for(int i=head[now];i!=-1;i=edge[i].nxt)
	{
		if(edge[i].v!=nowfa)
		{
			dfs1(edge[i].v,now,nowdeep+1);
			size[now]+=size[edge[i].v];
			if(son[now]==-1||size[edge[i].v]>size[son[now]])
				son[now]=edge[i].v;
		}
	}
}
void dfs2(int now,int nowid)
{
	tot++;
	pos[now]=tot;//更改當前節點的編號
	top[now]=nowid;
	if(!son[now])// 沒有重兒子
	 	return ;
	dfs2(son[now],nowid);// 在一條重鏈上
	for(int i=head[now];i!=-1;i=edge[i].nxt)
		if(deep[edge[i].v]>deep[edge[i].u]&&edge[i].v!=son[edge[i].u])
			dfs2(edge[i].v,edge[i].v);//自己和自己一條重鏈	
	return ; 
}
void build_tree(int k,int ll,int rr)
{
	tree[k].l=ll;tree[k].r=rr;
	if(tree[k].l==tree[k].r)
	{
		tree[k].maxn=tree[k].sum=0;
		return ;
	}
	int mid=(ll+rr)>>1;
	build_tree(ls,ll,mid);
	build_tree(rs,mid+1,rr);
	update(k);
}
void insert(int k,int pos,int val)
{
	if(tree[k].l==tree[k].r)
	{
		tree[k].maxn=tree[k].sum=val;
		return ;
	}
	int mid=(tree[k].l+tree[k].r)>>1;
	if(pos<=mid)
		insert(ls,pos,val);
	if(pos>mid)
		insert(rs,pos,val);
	update(k);
	
}
int querymax(int k,int ll,int rr)
{
	if(ll<=tree[k].l&&tree[k].r<=rr)
		return tree[k].maxn;
	int mid=(tree[k].l+tree[k].r)>>1,nowmax=-1;
	if(ll<=mid)
		nowmax=max(nowmax,querymax(ls,ll,rr));
	if(rr>mid)
		nowmax=max(nowmax,querymax(rs,ll,rr));
	return nowmax;
}
int askmax(int u,int v)
{
	
	int ans=-0x7ffff;
	while(top[u]!=top[v])//不在一條重鏈上
	{
		if(deep[top[u]]<deep[top[v]])
			swap(u,v);
		ans=max(ans,querymax(1,pos[top[u]],pos[u]));	
		u=fa[top[u]];
	}
	if(pos[u]>pos[v])
		swap(u,v);
	ans=max(ans,querymax(1,pos[u],pos[v]));
	return ans;
}
int querysum(int k,int ll,int rr)
{
	if(ll<=tree[k].l&&tree[k].r<=rr)
		return tree[k].sum;
	int mid=(tree[k].l+tree[k].r)>>1,nowsum=0;
	if(ll<=mid)
		nowsum+=querysum(ls,ll,rr);
	if(rr>mid)
		nowsum+=querysum(rs,ll,rr);
	return nowsum;
}
int asksum(int u,int v)
{
	int ans=0;
	while(top[u]!=top[v])
	{
		if(deep[top[u]]<deep[top[v]])
			swap(u,v);
		ans+=querysum(1,pos[top[u]],pos[u]);
		u=fa[top[u]];
	}
	if(pos[u]>pos[v])
		swap(u,v);
	ans+=querysum(1,pos[u],pos[v]);
	return ans;
}
int main()
{
	///freopen("bzoj_1036.in","r",stdin);
	//freopen("bzoj_1036.out","w",stdout);
	read(n);
	memset(head,-1,sizeof(head));
	//memset(son,-1,sizeof(son));
	for(int i=1;i<=n-1;i++)
	{
		int x,y;
		read(x);read(y);
		add_edge(x,y);
		add_edge(y,x);
	}
	for(int i=1;i<=n;i++)
		read(a[i]);
	dfs1(1,0,0);
	dfs2(1,1);
	build_tree(1,1,n);
	for(int i=1;i<=n;i++)
		insert(1,pos[i],a[i]);
	int q;
	read(q);
	for(int i=1;i<=q;i++)
	{
		string s;
		cin>>s;
		if(s[1]==‘H‘)// 修改 
		{
			int p,v;
			read(p);read(v);
			a[p]=v;
			insert(1,pos[p],v);
		}
		else if(s[1]==‘M‘)// 最大值 
		{
			int l,r;
			read(l);read(r);
			printf("%d\n",askmax(l,r));
		}
		else//求和 
		{
			int l,r;
			read(l);read(r);
			printf("%d\n",asksum(l,r));
		}
	}
	return 0;
}

  

P2590 [ZJOI2008]樹的統計