洛谷 P1505 [国家集训队]旅游

洛谷 P1505 [国家集训队]旅游

洛谷传送门

题目背景

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

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

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

题目描述

给定一棵 nn 个节点的树,边带权,编号 0 \sim n-10∼n−1,需要支持五种操作:

  • C i w 将输入的第 ii 条边权值改为 ww
  • N u v 将 u,vu,v 节点之间的边权都变为相反数
  • SUM u v 询问 u,vu,v 节点之间边权和
  • MAX u v 询问 u,vu,v 节点之间边权最大值
  • MIN u v 询问 u,vu,v 节点之间边权最小值

保证任意时刻所有边的权值都在 [-1000,1000][−1000,1000] 内。

输入格式

第一行一个正整数 nn,表示节点个数。
接下来 n-1n−1 行,每行三个整数 u,v,wu,v,w,表示 u,vu,v 之间有一条权值为 ww 的边,描述这棵树。
然后一行一个正整数 mm,表示操作数。
接下来 mm 行,每行表示一个操作。

输出格式

对于每一个询问操作,输出一行一个整数表示答案。


题解:

巨细节的一道题,并且,这道题的题解都是错的(我的是对的)(我好表脸)。

关于之前的题解(截止至2020.10.21之前)为什么错了,请见这个讨论:

关于题解错误的一些看法

很明显树剖。

树剖不会的走这边:

浅谈树链剖分

首先要边转点,边转点的规则是把边权转到儿子节点上。这样在链修改的时候,要刨除LCA的点权。很好理解。

然后是取相反数的操作。维护一个lazy标记,在打标记的时候容易发现的性质是:对于线段树上的当前节点,新和就是和取反,新最大值是原最小值取反,新最小值是原最大值取反。

那么这道题的思维部分就完事了,无脑开码即可。

注意几个蒟蒻曾经错过的细节:

首先,刨除LCA点权时,要判断x,y是否在一个点上,这时不需要刨,直接返回就行。

之后,lazy标记有没有重复标记。这是指,对于一个点,打两次lazy标记等于没打标记。这个可以通过异或运算来维护。

可以选择使用结构体存线段树,码量会少很多。当然也可以像蒟蒻,写很多函数来维护三个不同值,效果是一样的。

附上5K代码:

#include<cstdio>
#include<algorithm>
#define lson pos<<1
#define rson pos<<1|1
using namespace std;
const int maxn=2*1e5+10;
const int INF=1e9;
int n,m;
int tot,head[maxn],to[maxn<<1],nxt[maxn<<1],val[maxn<<1];
int cnt,son[maxn],top[maxn],id[maxn],deep[maxn],fa[maxn],size[maxn],a[maxn],w[maxn];
char opt[10];
int sum[maxn<<2],mx[maxn<<2],mn[maxn<<2];
int lazy[maxn<<2];
struct edge
{
	int x,y;
}idx[maxn];
int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<48||ch>57)
		if(ch=='-')
			f=-1,ch=getchar();
	while(ch>=48&&ch<=57)
		x=x*10+ch-48,ch=getchar();
	return x*f;
}
void add(int x,int y,int z)
{
	to[++tot]=y;
	nxt[tot]=head[x];
	val[tot]=z;
	head[x]=tot;
}
void dfs1(int x,int f)
{
	deep[x]=deep[f]+1;
	fa[x]=f;
	size[x]=1;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=to[i];
		if(y==f)
			continue;
		dfs1(y,x);
		a[y]=val[i];
		size[x]+=size[y];
		if(!son[x]||size[y]>size[son[x]])
			son[x]=y;
	}
}
void dfs2(int x,int t)
{
	top[x]=t;
	id[x]=++cnt;
	w[cnt]=a[x];
	if(!son[x])
		return;
	dfs2(son[x],t);
	for(int i=head[x];i;i=nxt[i])
	{
		int y=to[i];
		if(y==fa[x]||y==son[x])
			continue;
		dfs2(y,y);
	}
}
void pushup(int pos)
{
	sum[pos]=sum[lson]+sum[rson];
	mx[pos]=max(mx[lson],mx[rson]);
	mn[pos]=min(mn[lson],mn[rson]);
}
void build(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	if(l==r)
	{
		sum[pos]=mx[pos]=mn[pos]=w[l];
		return;
	}
	build(lson,l,mid);
	build(rson,mid+1,r);
	pushup(pos);
}
void mark(int pos,int l,int r)
{
	lazy[pos]^=1;
	int tmp1=-sum[pos],tmp2=-mn[pos],tmp3=-mx[pos];
	sum[pos]=tmp1;
	mx[pos]=tmp2;
	mn[pos]=tmp3;
}
void pushdown(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	if(lazy[pos])
	{
		mark(lson,l,mid);
		mark(rson,mid+1,r);
		lazy[pos]=0;
	}
}
void update(int pos,int l,int r,int x,int k)
{
	int mid=(l+r)>>1;
	if(l==r)
	{
		sum[pos]=mx[pos]=mn[pos]=k;
		return;
	}
	pushdown(pos,l,r);
	if(x<=mid)
		update(lson,l,mid,x,k);
	else
		update(rson,mid+1,r,x,k);
	pushup(pos);
}
void change(int pos,int l,int r,int x,int y)
{
	int mid=(l+r)>>1;
	if(x<=l && r<=y)
	{
		mark(pos,l,r);
		return;
	}
	pushdown(pos,l,r);
	if(x<=mid)
		change(lson,l,mid,x,y);
	if(y>mid)
		change(rson,mid+1,r,x,y);
	pushup(pos);
}
int query_sum(int pos,int l,int r,int x,int y)
{
	int ret=0;
	int mid=(l+r)>>1;
	if(x<=l && r<=y)
		return sum[pos];
	pushdown(pos,l,r);
	if(x<=mid)
		ret+=query_sum(lson,l,mid,x,y);
	if(y>mid)
		ret+=query_sum(rson,mid+1,r,x,y);
	return ret;
}
int query_max(int pos,int l,int r,int x,int y)
{
	int ret=-INF;
	int mid=(l+r)>>1;
	if(x<=l && r<=y)
		return mx[pos];
	pushdown(pos,l,r);
	if(x<=mid)
		ret=max(ret,query_max(lson,l,mid,x,y));
	if(y>mid)
		ret=max(ret,query_max(rson,mid+1,r,x,y));
	return ret;
}
int query_min(int pos,int l,int r,int x,int y)
{
	int ret=INF;
	int mid=(l+r)>>1;
	if(x<=l && r<=y)
		return mn[pos];
	pushdown(pos,l,r);
	if(x<=mid)
		ret=min(ret,query_min(lson,l,mid,x,y));
	if(y>mid)
		ret=min(ret,query_min(rson,mid+1,r,x,y));
	return ret;
}
void chain_upd(int x,int y)
{
	while(top[x]!=top[y])
	{
		if(deep[top[x]]<deep[top[y]])
			swap(x,y);
		change(1,1,n,id[top[x]],id[x]);
		x=fa[top[x]];
	}
	if(deep[x]<deep[y])
		swap(x,y);
	if(x!=y)
		change(1,1,n,id[y]+1,id[x]);
}
int q_sum(int x,int y)
{
	int ret=0;
	while(top[x]!=top[y])
	{
		if(deep[top[x]]<deep[top[y]])
			swap(x,y);
		ret+=query_sum(1,1,n,id[top[x]],id[x]);
		x=fa[top[x]];
	}
	if(deep[x]<deep[y])
		swap(x,y);
	if(x!=y)
		ret+=query_sum(1,1,n,id[y]+1,id[x]);
	return ret;
}
int q_max(int x,int y)
{
	int ret=-INF;
	while(top[x]!=top[y])
	{
		if(deep[top[x]]<deep[top[y]])
			swap(x,y);
		ret=max(ret,query_max(1,1,n,id[top[x]],id[x]));
		x=fa[top[x]];
	}
	if(deep[x]<deep[y])
		swap(x,y);
	if(x!=y)
		ret=max(ret,query_max(1,1,n,id[y]+1,id[x]));
	return ret;
}
int q_min(int x,int y)
{
	int ret=INF;
	while(top[x]!=top[y])
	{
		if(deep[top[x]]<deep[top[y]])
			swap(x,y);
		ret=min(ret,query_min(1,1,n,id[top[x]],id[x]));
		x=fa[top[x]];
	}
	if(deep[x]<deep[y])
		swap(x,y);
	if(x!=y)
		ret=min(ret,query_min(1,1,n,id[y]+1,id[x]));
	return ret;
}
int main()
{
	n=read();
	for(int i=1;i<n;i++)
	{
		int x,y,z;
		x=read();y=read();z=read();
		x++,y++;
		idx[i].x=x;
		idx[i].y=y;
		add(x,y,z);
		add(y,x,z);
	}
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	m=read();
	for(int i=1;i<=m;i++)
	{
		int a,b;
		scanf("%s%d%d",opt+1,&a,&b);
		if(opt[1]=='C')
		{
			int goal=deep[idx[a].x]>deep[idx[a].y]?idx[a].x:idx[a].y;
			update(1,1,n,id[goal],b);
		}
		else if(opt[1]=='N')
		{
			a++,b++;
			chain_upd(a,b);
		}
		else if(opt[1]=='S')
		{
			a++,b++;
			printf("%d\n",q_sum(a,b));
		}
		else if(opt[1]=='M'&&opt[2]=='A')
		{
			a++,b++;
			printf("%d\n",q_max(a,b));
		}
		else if(opt[1]=='M'&&opt[2]=='I')
		{
			a++,b++;
			printf("%d\n",q_min(a,b));
		}
	}
	return 0;
}
posted @ 2020-10-21 08:41  Seaway-Fu  阅读(167)  评论(0编辑  收藏  举报