ZJOI2008 树的统计

Description

  一棵树上有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本身

Input

  输入文件的第一行为一个整数n,表示节点的个数。
  接下来n–1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
  接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。
  接下来1行,为一个整数q,表示操作的总数。
  接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
  对于100%的数据,保证1 <= n <= 30000,0 <= q <= 200000;中途操作中保证每个节点的权值w在-30000到30000之间。

Output

  对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

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

Sample Output

4

1

2

2

10

6

5

6

5

16

树剖模板题。

//脱壳壳,结构体+inline+vector会re 
#include<bits/stdc++.h>
#define N 50001
using namespace std;
inline int get(){register int re=0,f=1;register char c;while(c=getchar(),(c>='0'&&c<='9')^1)f=c^'-';while(re=(re<<1)+(re<<3)+(c^48),c=getchar(),(c>='0'&&c<='9'));return f?re:-re;}
#define FOR(i,L,R) for(register int i=(L);i<=(R);++i)
#define REP(i,R,L) for(register int i=(R);i>=(L);--i)
int n,m,cnt;
struct Graph{//构图finish 
	vector<int>G[N];
	int p[N],fa[N];
	int siz[N],son[N],dep[N];
	int top[N];
	#define to G[x][i]
	inline void dfs2(int x,int sp){
		top[x]=sp;
		p[x]=++cnt;
		if(son[x])dfs2(son[x],sp);
		int sz=G[x].size()-1;
		FOR(i,0,sz)if(to^fa[x]&&to^son[x])dfs2(to,to);
	}
	inline void dfs1(int x,int Fa,int depth){
		int sz=G[x].size()-1;
		FOR(i,0,sz)if(to^Fa){
			dfs1(to,fa[to]=x,dep[to]=depth+1);
			siz[x]+=siz[to];
			if(siz[son[x]]<siz[to])son[x]=to;
		}
	}
	inline void init(){
		scanf("%d",&n);
		FOR(i,1,n-1){
			int x,y;scanf("%d%d",&x,&y);
			G[x].push_back(y);
			G[y].push_back(x);
		}FOR(i,1,n)siz[i]=1;
	}
}g;
#define top(a) g.top[a]
#define dep(a) g.dep[a]
#define p(a) g.p[a]
struct ZKW{
	int M;
	int k[N<<2],sum[N<<2]; 
	inline void Init(int x){
		memset(k,-63,sizeof(k));
		for(M=1;M<=x;M<<=1);
		FOR(i,1,x)k[M+p(i)]=sum[M+p(i)]=get();
		REP(i,M+x,1)sum[i>>1]+=sum[i];
		REP(i,M+x,1)k[i>>1]=max(k[i>>1],k[i]);
	}
	inline void Edit(int x,int v){
		k[M+x]=sum[M+x]=v;
		x+=M;
		while(x)k[x>>1]=max(k[x],k[x^1]),sum[x>>=1]=sum[x<<1]+sum[x<<1|1];
	}
	inline int Sum(int L,int r){
		int ans=0;
		for(register int s=M+L-1,t=M+r+1;s^t^1;s>>=1,t>>=1){
			if(~s&1)ans+=sum[s^1];
			if(t&1)ans+=sum[t^1];
		}return ans;
	}
	inline int Max(int L,int r){
		int ans=-1e8;
		for(register int s=M+L-1,t=M+r+1;s^t^1;s>>=1,t>>=1){
			if(~s&1)ans=max(ans,k[s^1]);
			if(t&1)ans=max(ans,k[t^1]);
		}return ans;
	}
}t;
inline void GETSUM(int x,int y){
	int t1=top(x),t2=top(y);
	int ans=0;
	while(t1!=t2){
		if(dep(t1)<dep(t2))swap(x,y),swap(t1,t2);
		ans+=t.Sum(p(t1),p(x));
		x=g.fa[t1];t1=top(x);
	}if(dep(x)>dep(y))swap(x,y);
	cout<<ans+t.Sum(p(x),p(y))<<"\n";
}
inline void GETMAX(int x,int y){
	int t1=top(x),t2=top(y);
	int ans=-1e8;
	while(t1!=t2){
		if(dep(t1)<dep(t2))swap(x,y),swap(t1,t2);
		ans=max(ans,t.Max(p(t1),p(x)));
		x=g.fa[t1];t1=top(x);
	}if(dep(x)>dep(y))swap(x,y);
	cout<<max(ans,t.Max(p(x),p(y)))<<"\n";
}
int main(){
	g.init();
	g.dfs1(1,g.fa[1]=0,g.dep[1]=1);
	g.dfs2(1,1);
	t.Init(cnt);
	scanf("%d",&m);
	FOR(i,1,m){
		char op[17];int x,y;
		scanf("%s%d%d",op+1,&x,&y);
		if(op[2]=='H')t.Edit(g.p[x],y);
		else if(op[2]=='S')GETSUM(x,y);
		else GETMAX(x,y);
	}return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值