#4479 长跑
题面
某校开展了同学们喜闻乐见的阳光长跑活动。为了能“为祖国健康工作五十年”,同学们纷纷离开寝室,离开教室,离开实验室,到操场参加3000米长跑运动。一时间操场上熙熙攘攘,摩肩接踵,盛况空前。
为了让同学们更好地监督自己,学校推行了刷卡机制。
学校中有n个地点,用1到n的整数表示,每个地点设有若干个刷卡机。
有以下三类事件:
1、修建了一条连接A地点和B地点的跑道。
2、A点的刷卡机台数变为了B。
3、进行了一次长跑。问一个同学从A出发,最后到达B最多可以刷卡多少次。具体的要求如下:
当同学到达一个地点时,他可以在这里的每一台刷卡机上都刷卡。但每台刷卡机只能刷卡一次,即使多次到达同一地点也不能多次刷卡。
为了安全起见,每条跑道都需要设定一个方向,这条跑道只能按照这个方向单向通行。最多的刷卡次数即为在任意设定跑道方向,按照任意路径从A地点到B地点能刷卡的最多次数。
输入
输入的第一行包含两个正整数n,m,表示地点的个数和操作的个数。
第二行包含n个非负整数,其中第i个数为第个地点最开始刷卡机的台数。
接下来有m行,每行包含三个非负整数P,A,B,P为事件类型,A,B为事件的两个参数。
最初所有地点之间都没有跑道。
每行相邻的两个数之间均用一个空格隔开。表示地点编号的数均在1到n之间,每个地点的刷卡机台数始终不超过10000,P=1,2,3。
输出
输出的行数等于第3类事件的个数,每行表示一个第3类事件。如果该情况下存在一种设定跑道方向的方案和路径的方案,可以到达,则输出最多可以刷卡的次数。如果A不能到达B,则输出-1。
样例输入
9 31
10 20 30 40 50 60 70 80 90
3 1 2
1 1 3
1 1 2
1 8 9
1 2 4
1 2 5
1 4 6
1 4 7
3 1 8
3 8 8
1 8 9
3 8 8
3 7 5
3 7 3
1 4 1
3 7 5
3 7 3
1 5 7
3 6 5
3 3 6
1 2 4
1 5 5
3 3 6
2 8 180
3 8 8
2 9 190
3 9 9
2 5 150
3 3 6
2 1 210
3 3 6
样例输出
-1
-1
80
170
180
170
190
170
250
280
280
270
370
380
580
提示
对于100%的数据,m<=5∗nm<=5*nm<=5∗n,任意时刻,每个地点的刷卡机台数不超过10000。N<=1.5×105N<=1.5×10^5N<=1.5×105
SOL
LCT维护的是森林,如果有环就变为带边双的
森林。
本题只有加边,考虑加入一条边增加
一个环后,需要缩点来保持森林状态。采用
并查集来维护环的信息。
1.加边的操作有两种情况,如果本身就不在同一联通块就加一条边即可,else,直接更新一下子树信息即可。
2.修改操作可以access一下x点,把x点splay到根,然后修改
3.询问操作,只要不在同一联通块中就puts(“-1”)
More importantly,这道题必须加读入优化和输出优化,否则会TLE一个点……
代码:
#include<bits/stdc++.h>
#define N 150005
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd(){
char ch=nc();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
inline void write(int x){if(!x)return;write(x/10);putchar(x%10+'0');}
int f[N],fa[N],rev[N],ch[N][2],mx[N],val[N],top,stk[N],n,m,bcc[N],a[N];
inline int findbcc(int x){return bcc[x]==x?x:bcc[x]=findbcc(bcc[x]);}
inline int findfa(int x){return f[x]==x?x:f[x]=findfa(f[x]);}
inline int get(int x){return x==ch[findbcc(fa[x])][1];}
inline int isrt(int x){int f=findbcc(fa[x]);return !f||(x!=ch[f][0]&&x!=ch[f][1]);}
inline void pushdown(int x){
if(!rev[x])return;
swap(ch[x][0],ch[x][1]);
rev[ch[x][0]]^=1;rev[ch[x][1]]^=1;rev[x]=0;
}
inline void pushup(int x){mx[x]=val[x]+mx[ch[x][0]]+mx[ch[x][1]];}
inline void rotate(int x){
int y=fa[x],z=fa[y],d=get(x);
if(!isrt(y))ch[z][ch[z][1]==y]=x;
fa[x]=z;fa[y]=x;ch[y][d]=ch[x][d^1];
ch[x][d^1]=y;fa[ch[y][d]]=y;
pushup(y),pushup(x);
}
inline void splay(int x){
stk[top=1]=x;
for(int register i=x;!isrt(i);i=findbcc(fa[i]))stk[++top]=findbcc(fa[i]);
for(;top;top--)pushdown(stk[top]),fa[stk[top]]=findbcc(fa[stk[top]]);
for(int register y=fa[x];!isrt(x);rotate(x),y=fa[x])
if(!isrt(y))rotate(get(x)==get(y)?y:x);
}
inline void access(int x){for(int register y=0;x;y=x,x=findbcc(fa[x]))splay(x),ch[x][1]=y,pushup(x);}
inline void makert(int x){access(x);splay(x);rev[x]^=1;}
inline void hchain(int x,int y){makert(x);access(y);splay(y);}
inline void link(int x,int y){makert(x);fa[x]=y;}
inline void merge(int x,int y){
bcc[findbcc(x)]=findbcc(y);pushdown(x);
if(x!=y)val[y]+=val[x];
if(ch[x][0])merge(ch[x][0],y);
if(ch[x][1])merge(ch[x][1],y);
ch[x][1]=ch[x][0]=0;
}
signed main(){
n=rd();m=rd();
for(int register i=1;i<=n;i++){val[i]=rd();a[i]=val[i];bcc[i]=i;f[i]=i;}
while(m--){
int op=rd(),x=rd(),y=rd();
if(op==1){
x=findbcc(x),y=findbcc(y);
if(x==y)continue;
int fx=findfa(x),fy=findfa(y);
if(fx!=fy){f[fy]=fx;link(x,y);}
else{hchain(x,y);merge(y,y);pushup(y);}
}
if(op==2){
int ne=x;
x=findbcc(x);
access(x);splay(x);val[x]+=y-a[ne];a[ne]=y;
pushup(x);
}
if(op==3){
x=findbcc(x);y=findbcc(y);
if(findfa(x)!=findfa(y))puts("-1");
else{hchain(x,y);if(mx[y])write(mx[y]);else putchar('0');putchar('\n');}
}
}
}