ural 1553 树剖+线段树

//链式前向星版
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
//建图
int to[maxn*2],nex[maxn*2],beg[maxn],tot; 
//树剖预处理
int fa[maxn],dis[maxn],siz[maxn],son[maxn];
//树剖成一条链
int top[maxn], id[maxn],ran[maxn],cnt;
//线段树
int Max[maxn<<2]; 

int n,q;
//添加边 
void add(int x,int y){
	to[++tot]=y;
	nex[tot]=beg[x];	
	beg[x]=tot;	
}
//树剖预处理
void dfs1(int rt,int ba){
	siz[rt]=1;
	dis[rt]=dis[ba]+1;
	for(int i=beg[rt];i;i=nex[i]){
		int u=to[i];
		if(u!=ba){
			fa[u]=rt;
			dfs1(u,rt);
			siz[rt]+=siz[u];
			if(siz[u]>siz[son[rt]])son[rt]=u;
		}
	}
} 
//树剖成一条链
void dfs2(int rt,int tp){
	top[rt]=tp;
	id[++cnt]=rt;	
	ran[rt]=cnt;
	if(son[rt])dfs2(son[rt],tp);
	for(int i=beg[rt];i;i=nex[i]){
		int u=to[i];
		if(u!=son[rt] && u!=fa[rt])
			dfs2(u,u);
	}	
} 
//线段树更新
void update(int rt,int l,int r,int pos,int x){
	if(l==r && l==pos){
		Max[rt] +=x;
		return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid)
		update(rt<<1,l,mid,pos,x);
	else
		update(rt<<1|1,mid+1,r,pos,x);
	Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
} 
//线段树查询
int query(int rt,int l,int r,int L ,int R){
	if(L<=l && r<=R)
		return Max[rt];
	else{
		int tmp=0;
		int mid=(l+r)>>1;
		if(L<=mid)
			tmp=max(tmp,query(rt<<1,l,mid,L,R));
		if(mid+1<=R)
			tmp=max(tmp,query(rt<<1|1,mid+1,r,L,R));
		return tmp;
	}
} 
//主程序 
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d %d",&x,&y);
		add(x,y);	add(y,x);
	}
	dfs1(1,0);
	dfs2(1,1);
	cin>>q;getchar();
	for(int i=1;i<=q;i++){
		char op;
		int x,y;
		scanf("%c %d %d",&op,&x,&y);
		getchar();
		if(op=='I')
			update(1,1,n,ran[x],y);
		else{
			int ans=0;
			while(top[x]!=top[y]){
				if(dis[top[x]]<dis[top[y]])swap(x,y);
				ans=max(ans,query(1,1,n,ran[top[x]],ran[x]));	
				x=fa[top[x]];		
			}
			if(dis[x]>dis[y])swap(x,y);
			ans=max(ans,query(1,1,n,ran[x],ran[y]));
			printf("%d\n",ans);
		}
	}
	return 0;
}

//VECTOR版
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
//建图
vector<int>a[maxn];
//树剖预处理
int fa[maxn],dis[maxn],siz[maxn],son[maxn];
//树剖成一条链
int top[maxn], id[maxn],ran[maxn],cnt;
//线段树
int Max[maxn<<2]; 

int n,q;

void dfs1(int rt,int ba){
	siz[rt]=1;
	dis[rt]=dis[ba]+1;
	for(int i=0;i<a[rt].size();i++){
		int u=a[rt][i];
		if(u!=ba){
			fa[u]=rt;
			dfs1(u,rt);
			siz[rt]+=siz[u];
			if(siz[u]>siz[son[rt]])son[rt]=u;
		}
	}
} 
//树剖成一条链
void dfs2(int rt,int tp){
	top[rt]=tp;
	id[++cnt]=rt;	
	ran[rt]=cnt;
	if(son[rt])dfs2(son[rt],tp);
	for(int i=0;i<a[rt].size();i++){
		int u=a[rt][i];
		if(u!=son[rt] && u!=fa[rt])
			dfs2(u,u);
	}	
} 
//线段树更新
void update(int rt,int l,int r,int pos,int x){
	if(l==r && l==pos){
		Max[rt] +=x;
		return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid)
		update(rt<<1,l,mid,pos,x);
	else
		update(rt<<1|1,mid+1,r,pos,x);
	Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
} 
//线段树查询
int query(int rt,int l,int r,int L ,int R){
	if(L<=l && r<=R)
		return Max[rt];
	else{
		int tmp=0;
		int mid=(l+r)>>1;
		if(L<=mid)
			tmp=max(tmp,query(rt<<1,l,mid,L,R));
		if(mid+1<=R)
			tmp=max(tmp,query(rt<<1|1,mid+1,r,L,R));
		return tmp;
	}
} 
//主程序 
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d %d",&x,&y);
		a[x].push_back(y);
		a[y].push_back(x);
	}
	dfs1(1,0);
	dfs2(1,1);
	cin>>q;getchar();
	for(int i=1;i<=q;i++){
		char op;
		int x,y;
		scanf("%c %d %d",&op,&x,&y);
		getchar();
		if(op=='I')
			update(1,1,n,ran[x],y);
		else{
			int ans=0;
			while(top[x]!=top[y]){
				if(dis[top[x]]<dis[top[y]])swap(x,y);
				ans=max(ans,query(1,1,n,ran[top[x]],ran[x]));	
				x=fa[top[x]];		
			}
			if(dis[x]>dis[y])swap(x,y);
			ans=max(ans,query(1,1,n,ran[x],ran[y]));
			printf("%d\n",ans);
		}
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值