[国家集训队]旅游

题目描述
Ray 乐忠于旅游,这次他来到了T 城。T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有N − 1 座桥。

Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度w,也就是说,Ray 经过这座桥会增加w 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。

现在,Ray 想让你帮他计算从u 景点到v 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。

输入格式
输入的第一行包含一个整数N,表示T 城中的景点个数。景点编号为 0…N − 1。

接下来N − 1 行,每行三个整数u、v 和w,表示有一条u 到v,使 Ray 愉悦度增加w 的桥。桥的编号为1…N − 1。|w| <= 1000。 输入的第N + 1 行包含一个整数M,表示Ray 的操作数目。

接下来有M 行,每行描述了一个操作,操作有如下五种形式:

C i w,表示Ray 对于经过第i 座桥的愉悦度变成了w。

N u v,表示Ray 对于经过景点u 到v 的路径上的每一座桥的愉悦度都变成原来的相反数。

SUM u v,表示询问从景点u 到v 所获得的总愉悦度。

MAX u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最大愉悦度。

MIN u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最小愉悦度。

测试数据保证,任意时刻,Ray 对于经过每一座桥的愉悦度的绝对值小于等于1000。

输出格式
对于每一个询问(操作S、MAX 和MIN),输出答案。

输入输出样例
输入 #1 复制

3
0 1 1
1 2 2
8
SUM 0 2
MAX 0 2
N 0 1
SUM 0 2
MIN 0 2
C 1 3
SUM 0 2
MAX 0 2
输出 #1 复制
3
2
1
-1
5
3
说明/提示
很容易的基础题哦>.<


不是很难,但是很恶心的一道树剖,聚聚帮我debug(在此感谢),QAQ,


这道题需要维护的信息挺多的,最大值,最小值,区间和,还有一个就是给出的是边的信息,然后树剖维护点,所以我们要把边变成点,怎么变呢?一般来说就两种办法,把边拆成两个点,或者把边用下面的点(深度深的点)来表示(点是唯一的,表示这条边),这样就可以了。所以我们写个裸的树剖就好了,写到自闭。QAQ(还是老老实实跟大佬写 LCT 吧)。这道题还有一个需要注意的点,就是对于两个点之间的桥,因为我们是用下面的点来表示这条边,所以更新的时候从上面的点下面那个点开始更新即可 updata(1,pos[x]+1,pos[y]);


#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,m,a[N],b[N],c[N],h[N],f[N],sz[N],bl[N],pos[N],cnt=0;
int head[N],nex[N<<1],to[N<<1],tot;
struct node{
	int l,r,add,sum,max,min;
}t[N<<2];
inline void add(int a,int b){
	to[++tot]=b; nex[tot]=head[a]; head[a]=tot;
}
void dfs1(int x){
	sz[x]=1;
	for(int i=head[x];i;i=nex[i]){
		if(to[i]==f[x])	return ;
		f[to[i]]=x;	h[to[i]]=h[x]+1; 
		dfs1(to[i]);	sz[x]+=sz[to[i]];
	}
}
void dfs2(int x,int belong){
	int k=0;	pos[x]=++cnt;	bl[x]=belong;
	for(int i=head[x];i;i=nex[i])
		if(h[to[i]]>h[x]&&sz[to[i]]>sz[k])	k=to[i];
	if(!k)	return ;	dfs2(k,belong);
	for(int i=head[x];i;i=nex[i])
		if(h[to[i]]>h[x]&&to[i]!=k)	dfs2(to[i],to[i]);
}
inline void push_up(int p){
	t[p].max=max(t[p<<1].max,t[p<<1|1].max);
	t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
	t[p].min=min(t[p<<1].min, t[p<<1|1].min);
}
inline void push_down(int p){
	if(t[p].add==-1){
		swap(t[p<<1].max,t[p<<1].min);
		swap(t[p<<1|1].max,t[p<<1|1].min);
		t[p<<1].max*=-1;	t[p<<1].min*=-1;
		t[p<<1|1].max*=-1;	t[p<<1|1].min*=-1;
		t[p<<1].sum*=-1;	t[p<<1|1].sum*=-1;
		t[p<<1].add*=-1; t[p<<1|1].add*=-1; 
		t[p].add=1;
	}
}
void build(int p,int l,int r){
	t[p].l=l;	t[p].r=r; t[p].add = 1;
	if(l==r)	return ;	int mid=l+r>>1;
	build(p<<1,l,mid);	build(p<<1|1,mid+1,r);
}
void change(int p,int x,int v){
	if(t[p].l==t[p].r){
		t[p].sum=t[p].max=t[p].min=v;	return ;
	}
	push_down(p);	int mid=t[p].l+t[p].r>>1;
	if(x<=mid)	change(p<<1,x,v);
	else	change(p<<1|1,x,v);
	push_up(p);	
}
void updata(int p,int l,int r){
	if(t[p].l==l&&t[p].r==r){
		t[p].sum*=-1;	swap(t[p].max,t[p].min);
		t[p].max*=-1;	t[p].min*=-1;	t[p].add*=-1;	return ;
	}
	push_down(p);	int mid=t[p].l+t[p].r>>1;
	if(r<=mid)	updata(p<<1,l,r);
	else if(l>mid)	updata(p<<1|1,l,r);
	else	updata(p<<1,l,mid),updata(p<<1|1,mid+1,r);
	push_up(p);
}
int ask(int p,int l,int r,int k){
	if(t[p].l==l&&t[p].r==r)	return (k?t[p].max:t[p].min);
	int mid=t[p].l+t[p].r>>1;
	push_down(p);
	if(r<=mid)	return ask(p<<1,l,r,k);
	else if(l>mid)	return ask(p<<1|1,l,r,k);
	else{
		if(k)	return max(ask(p<<1,l,mid,k),ask(p<<1|1,mid+1,r,k));
		else	return min(ask(p<<1,l,mid,k),ask(p<<1|1,mid+1,r,k));
	}
}
int asksum(int p,int l,int r){
	if(t[p].l==l&&t[p].r==r)	return t[p].sum;
	int mid=t[p].l+t[p].r>>1;
	push_down(p);
	if(r<=mid)	return asksum(p<<1,l,r);
	else if(l>mid)	return asksum(p<<1|1,l,r);
	else	return asksum(p<<1,l,mid)+asksum(p<<1|1,mid+1,r);
}
void flip(int x,int y){
	while(bl[x]!=bl[y]){
		if(h[bl[x]]<h[bl[y]])	swap(x,y);
		updata(1,pos[bl[x]],pos[x]);	x=f[bl[x]];
	}
	if(pos[x]==pos[y])	return ;
	if(pos[x]>pos[y])	swap(x,y);
	updata(1,pos[x]+1,pos[y]);
}
int query(int x,int y,int k){
	int res=0x3f3f3f3f;	if(k)	res*=-1;
	while(bl[x]!=bl[y]){
		if(h[bl[x]]<h[bl[y]])	swap(x,y);
		if(k)	res=max(res,ask(1,pos[bl[x]],pos[x],1));
		else	res=min(res,ask(1,pos[bl[x]],pos[x],0));
		x=f[bl[x]];
	}
	if(pos[x]==pos[y])	return res;
	if(pos[x]>pos[y])	swap(x,y);
	if(k)	res=max(res,ask(1,pos[x]+1,pos[y],1));
	else	res=min(res,ask(1,pos[x]+1,pos[y],0));
	return res;
}
int querysum(int x,int y){
	int res=0;
	while(bl[x]!=bl[y]){
		if(h[bl[x]]<h[bl[y]])	swap(x,y);
		res+=asksum(1,pos[bl[x]],pos[x]);
		x=f[bl[x]];
	}
	if(pos[x]==pos[y])	return res;
	if(pos[x]>pos[y])	swap(x,y);
	res+=asksum(1,pos[x]+1,pos[y]);
	return res;
}
signed main(){
	scanf("%d",&n);	build(1,1,n);
	for(int i=1;i<n;i++){
		scanf("%d %d %d",&a[i],&b[i],&c[i]);	a[i]++;	b[i]++;
		add(a[i],b[i]);	add(b[i],a[i]);
	}
	dfs1(1);	dfs2(1,1);
	for(int i=1;i<n;i++){
		change(1,max(pos[a[i]],pos[b[i]]),c[i]);
	}
	scanf("%d",&m);	char op[10];
	while(m--){
		int x,y;	scanf("%s %d %d",op,&x,&y);	x++; y++;
		if(op[0]=='C')	change(1,max(pos[a[x-1]],pos[b[x-1]]),y-1);
		else if(op[0]=='N')	flip(x,y);
		else if(op[0]=='S')	printf("%d\n",querysum(x,y));
		else if(op[1]=='A')	printf("%d\n",query(x,y,1));
		else	printf("%d\n",query(x,y,0));
	}
	return 0;
}
全部评论

相关推荐

10-07 23:57
已编辑
电子科技大学 Java
八街九陌:博士?客户端?开发?啊?
点赞 评论 收藏
分享
10-25 00:32
香梨想要offer:感觉考研以后好好学 后面能乱杀,目前这简历有点难
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务