【UOJ274】【清华集训2016】温暖会指引我们前行 LCT

【UOJ274】【清华集训2016】温暖会指引我们前行

任务描述

虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低。

小R的宿舍楼中有n个地点和一些路,一条路连接了两个地点,小R可以通过这条路从其中任意一个地点到达另外一个地点。但在刚开始,小R还不熟悉宿舍楼中的任何一条路,所以他会慢慢地发现这些路,他在发现一条路时还会知道这条路的温度和长度。每条路的温度都是互不相同的。

小R需要在宿舍楼中活动,每次他都需要从一个地点到达另一个地点。小R希望每次活动时经过一条最温暖的路径,最温暖的路径的定义为,将路径上各条路的温度从小到大排序后字典序最大。即温度最低的路温度尽量高,在满足该条件的情况下,温度第二低的路温度尽量高,以此类推。小R不会经过重复的路。由于每条路的温度互不相同,因此只存在一条最温暖的路径。

对于小R的每次活动,你需要求出小R需要走过的路径总长度。如果小R通过当前发现的路不能完成这次活动,则输出1

注意本题中的字典序与传统意义上的字典序定义有所不同,对于两个序列a,b(ab),若a是b的前缀则a的字典序较大,同时可以推出空串的字典序最大。

输入格式

第一行两个正整数n,m。表示小R的宿舍楼中有n个地点,共发生了m个事件。

接下来m行,每行描述一个事件,事件分为三类。

  1. findiduvtl表示小R发现了一条连接u和v之间的路,编号为id。相同id的边只会出现一次。

  2. moveuv表示小R要从u到达v,你需要计算出最温暖的路径的长度 ,若不能从u到达v,则输出−1。

  3. changeidl表示从u到v这条边的长度变为了l(保证在当前时间点这条边存在)。

输出格式

对于每个询问,输出一行整数,表示最温暖的路径长度。

题解:裸题,直接用LCT维护最大生成树即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=100010;
int n,m,tot;
struct LCT
{
	int ch[2],fa,rev,v,vn,l,sl;
}s[maxn<<2];
int f[maxn],pa[maxn<<2],pb[maxn<<2];
char str[10];
inline bool isr(int x) {return (s[s[x].fa].ch[0]!=x)&&(s[s[x].fa].ch[1]!=x);}
inline void pushdown(int x)
{
	if(s[x].rev)
	{
		swap(s[x].ch[0],s[x].ch[1]);
		if(s[x].ch[0])	s[s[x].ch[0]].rev^=1;
		if(s[x].ch[1])	s[s[x].ch[1]].rev^=1;
		s[x].rev=0;
	}
}
inline int MN(int a,int b) {return s[a].v<s[b].v?a:b;}
inline void pushup(int x)
{
	s[x].vn=MN(MN(s[s[x].ch[0]].vn,s[s[x].ch[1]].vn),x);
	s[x].sl=s[s[x].ch[0]].sl+s[s[x].ch[1]].sl+s[x].l;
}
inline void rotate(int x)
{
	int y=s[x].fa,z=s[y].fa,d=(x==s[y].ch[1]);
	if(!isr(y))	s[z].ch[y==s[z].ch[1]]=x;
	s[x].fa=z,s[y].fa=x,s[y].ch[d]=s[x].ch[d^1];
	if(s[x].ch[d^1])	s[s[x].ch[d^1]].fa=y;
	s[x].ch[d^1]=y;
	pushup(y),pushup(x);
}
void updata(int x)
{
	if(!isr(x))	updata(s[x].fa);
	pushdown(x);
}
inline void splay(int x)
{
	updata(x);
	while(!isr(x))
	{
		int y=s[x].fa,z=s[y].fa;
		if(!isr(y))
		{
			if((x==s[y].ch[0])^(y==s[z].ch[0]))	rotate(x);
			else	rotate(y);
		}
		rotate(x);
	}
}
inline void access(int x)
{
	for(int y=0;x;splay(x),s[x].ch[1]=y,pushup(x),y=x,x=s[x].fa);
}
inline void maker(int x)
{
	access(x),splay(x),s[x].rev^=1;
}
inline void link(int x,int y)
{
	maker(y),s[y].fa=x;
}
inline void cut(int x,int y)
{
	maker(x),access(y),splay(y),s[y].ch[0]=s[x].fa=0,pushup(x),pushup(y);
}
int find(int x)
{
	return (f[x]==x)?x:(f[x]=find(f[x]));
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
	return ret*f;
}
int main()
{
	//freopen("bz4736.in","r",stdin);
	s[0].v=1<<30;
	n=rd(),m=rd();
	int i,a,b,c,e;
	for(i=1;i<=n;i++)	f[i]=i,s[i].v=1<<30,s[i].vn=i;
	for(i=1;i<=m;i++)
	{
		scanf("%s",str);
		if(str[0]=='f')
		{
			e=n+rd()+1,a=pa[e]=rd()+1,b=pb[e]=rd()+1,s[e].v=rd(),s[e].vn=e,s[e].l=s[e].sl=rd();
			if(find(a)==find(b))
			{
				maker(a),access(b),splay(b),c=s[s[b].ch[0]].vn;
				if(s[c].v<s[e].v)	cut(c,pa[c]),cut(c,pb[c]),link(a,e),link(b,e);
			}
			else	f[f[a]]=f[b],link(a,e),link(b,e);
		}
		if(str[0]=='m')
		{
			a=rd()+1,b=rd()+1;
			if(find(a)!=find(b))	puts("-1");
			else	maker(a),access(b),splay(b),printf("%d\n",s[s[b].ch[0]].sl);
		}
		if(str[0]=='c')	e=n+rd()+1,splay(e),s[e].l=rd(),pushup(e);
	}
	return 0;
}

相关推荐