时间限制:2s2s
空间限制:512MB
任务描述
虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低。
小R的宿舍楼中有n个地点和一些路,一条路连接了两个地点,小R可以通过这条路从其中任意一个地点到达另外一个地点。但在刚开始,小R还不熟悉宿舍楼中的任何一条路,所以他会慢慢地发现这些路,他在发现一条路时还会知道这条路的温度和长度。每条路的温度都是互不相同的。
小R需要在宿舍楼中活动,每次他都需要从一个地点到达另一个地点。小R希望每次活动时经过一条最温暖的路径,最温暖的路径的定义为,将路径上各条路的温度从小到大排序后字典序最大。即温度最低的路温度尽量高,在满足该条件的情况下,温度第二低的路温度尽量高,以此类推。小R不会经过重复的路。由于每条路的温度互不相同,因此只存在一条最温暖的路径。
对于小R的每次活动,你需要求出小R需要走过的路径总长度。如果小R通过当前发现的路不能完成这次活动,则输出 −1。
注意本题中的字典序与传统意义上的字典序定义有所不同,对于两个序列a,b(a≠b),若a是b的前缀则a的字典序较大,同时可以推出空串的字典序最大。
输入格式
第一行两个正整数 n,m。表示小R的宿舍楼中有 n 个地点,共发生了 m 个事件。
接下来 m 行,每行描述一个事件,事件分为三类。
find id u v t l 表示小R发现了一条连接u和v之间的路,编号为id。相同id的边只会出现一次。
move u v表示小R要从u到达v,你需要计算出最温暖的路径的长度 ,若不能从u到达v,则输出−1
change id l表示从u到v这条边的长度变为了l(保证在当前时间点这条边存在)。
输出格式
对于每个询问,输出一行整数,表示最温暖的路径长度。
限制与约定
对于find操作:
(
0
≤
i
d
<
m
,
0
≤
u
,
v
<
n
,
u
≠
v
,
0
≤
t
≤
1000000000
,
0
≤
l
≤
10000
)
(0≤id<m,0≤u,v<n,u≠v,0≤t≤1000000000,0≤l≤10000)
(0≤id<m,0≤u,v<n,u̸=v,0≤t≤1000000000,0≤l≤10000)
对于move操作:
(
0
≤
u
,
v
<
n
)
(0≤u,v<n)
(0≤u,v<n)
对于change操作:
(
0
≤
l
≤
10000
)
(0≤l≤10000)
(0≤l≤10000)
对于100%的数据,
1
≤
n
≤
100000
,
1
≤
m
≤
300000
1≤n≤100000,1≤m≤300000
1≤n≤100000,1≤m≤300000
测试点 | n | m | 其它 |
---|---|---|---|
1-2 | <=20 | <=50 | 无特殊约定 |
3-5 | <=1000 | <=3000 | |
6-10 | <=100000 | <=300000 | 所有的find事件都在move事件之前,且没有change事件 |
11-14 | 所有的find事件都在move事件之前 | ||
15-20 | 无特殊约定 |
题目分析
久违的复习了一下LCT
都是很基础的LCT操作
每次加边时检查
u
,
v
u,v
u,v是否连通,若不连通则直接加边
若以连通则查找
u
,
v
u,v
u,v路径上温暖度最小的边,若小于当前边则直接替换
维护连通性最好用并查集,树上直接判连通容易T
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lt;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return x*f;
}
const lt inf=2e9;
const int maxn=500010;
int n,m;
int fa[maxn],ch[maxn][2];
int mi[maxn],val[maxn],lzy[maxn];
lt dis[maxn],sum[maxn];
int st[maxn],ff[maxn];
int Eu[maxn],Ev[maxn];
char ss[20];
int isrt(int x)
{
return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
void push(int x)
{
if(!lzy[x]) return;
swap(ch[x][0],ch[x][1]);
lzy[ch[x][0]]^=1; lzy[ch[x][1]]^=1;
lzy[x]=0;
}
void update(int x)
{
int lc=ch[x][0],rc=ch[x][1];
mi[x]=x;
mi[x]=val[mi[lc]]<val[mi[x]]?mi[lc]:mi[x];
mi[x]=val[mi[rc]]<val[mi[x]]?mi[rc]:mi[x];
sum[x]=sum[lc]+sum[rc]+dis[x];
}
void rotate(int x)
{
int y=fa[x],z=fa[y];
int d=(ch[y][0]==x);
if(!isrt(y))
{
if(ch[z][0]==y) ch[z][0]=x;
else ch[z][1]=x;
}
fa[y]=x; fa[ch[x][d]]=y; fa[x]=z;
ch[y][d^1]=ch[x][d]; ch[x][d]=y;
update(y); update(x);
}
void splay(int x)
{
int top=0; st[++top]=x;
for(int i=x;!isrt(i);i=fa[i])
st[++top]=fa[i];
while(top) push(st[top--]);
while(!isrt(x))
{
int y=fa[x],z=fa[y];
if(!isrt(y))
{
if((ch[z][0]==y)^(ch[y][0]==x)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x)
{
int t=0;
while(x)
{
splay(x);
ch[x][1]=t;
update(x);
t=x; x=fa[x];
}
}
void mkrt(int x)
{
access(x); splay(x);
lzy[x]^=1;
}
void match(int x,int y)
{
mkrt(x); fa[x]=y;
}
void cut(int x,int y)
{
mkrt(x);
access(y); splay(y);
fa[x]=ch[y][0]=0;
update(y);
}
int find(int x)
{
if(x==ff[x]) return x;
else return ff[x]=find(ff[x]);
}
int qmin(int x,int y)
{
mkrt(x);
access(y); splay(y);
return mi[y];
}
void path()
{
int id=read()+1+n;
int u=read()+1,v=read()+1;
Eu[id]=u; Ev[id]=v;
val[id]=read(); dis[id]=read();
int fu=find(u),fv=find(v);
if(fu!=fv)
{
ff[fu]=fv;
match(u,id); match(id,v);
}
else
{
int num=qmin(u,v);
if(val[num]<val[id])
{
cut(Eu[num],num); cut(num,Ev[num]);
match(u,id); match(id,v);
}
}
}
lt qsum(int x,int y)
{
mkrt(x);
access(y); splay(y);
return sum[y];
}
lt query()
{
int u=read()+1,v=read()+1;
if(find(u)!=find(v)) return -1;
else return qsum(u,v);
}
void change()
{
int id=read()+1+n;
mkrt(id);
dis[id]=read();
update(id);
}
int main()
{
n=read();m=read();
for(int i=0;i<=n;++i)
val[i]=inf,ff[i]=i;
for(int i=1;i<=m;++i)
{
scanf("%s",&ss);
if(ss[0]=='f') path();
else if(ss[0]=='m') printf("%lld\n",query());
else if(ss[0]=='c') change();
}
return 0;
}