[LCT BZOJ]2959: 长跑

1 篇文章 0 订阅

2959: 长跑

 某校开展了同学们喜闻乐见的阳光长跑活动。为了能“为祖国健康工作五十年”,同学们纷纷离开寝室,离开教室,离开实验室,到操场参加3000米长跑运动。一时间操场上熙熙攘攘,摩肩接踵,盛况空前。
  为了让同学们更好地监督自己,学校推行了刷卡机制。
  学校中有n个地点,用1到n的整数表示,每个地点设有若干个刷卡机。
  有以下三类事件:
  1、修建了一条连接A地点和B地点的跑道。
  2、A点的刷卡机台数变为了B。
  3、进行了一次长跑。问一个同学从A出发,最后到达B最多可以刷卡多少次。具体的要求如下:
  当同学到达一个地点时,他可以在这里的每一台刷卡机上都刷卡。但每台刷卡机只能刷卡一次,即使多次到达同一地点也不能多次刷卡。
  为了安全起见,每条跑道都需要设定一个方向,这条跑道只能按照这个方向单向通行。最多的刷卡次数即为在任意设定跑道方向,按照任意路径从A地点到B地点能刷卡的最多次数。

用LCT维护双联通
代码丑:

#include<cstdio>
#include<algorithm>
using namespace std;
#define N 200000
#define fa(x) (a.find(fa[x]))
#define f(x) (a.find(x))
#define son(x) (ch[fa(x)][1]==x)
inline char tc(void){
    static char fl[10000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,10000,stdin),A==B)?EOF:*A++;
}
inline int read(void){
    int a=0;char c;while((c=tc())<'0'||c>'9');
    while(c>='0'&&c<='9')a=a*10+c-'0',c=tc();return a;
}
struct cet{
    int f[N+5];
    inline void init(int n){for(int i=1;i<=n;++i)f[i]=i;}
    int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
    void merge(int x,int y){f[find(x)]=find(y);}
}a,b;
int n,m,fa[N+5],ch[N+5][2],v[N+5],t[N+5],sum[N+5];
bool rev[N+5];
inline bool isroot(int x){return ch[fa(x)][1]!=x&&ch[fa(x)][0]!=x;}
inline void update(int x){sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+v[x];}
inline void push(int x){if(rev[x])rev[x]^=1,rev[ch[x][0]]^=1,rev[ch[x][1]]^=1,swap(ch[x][0],ch[x][1]);}
inline void rotate(int x){
    int y=fa(x),z=fa(y),o=son(x);
    if(!isroot(y))ch[z][son(y)]=x;
    fa[x]=z,fa[y]=x;if(ch[x][!o])fa[ch[x][!o]]=y;
    ch[y][o]=ch[x][!o];ch[x][!o]=y,
    update(y),update(x);
}
inline void splay(int x){
    static int st[N+5],top;
    top=0,st[++top]=x;
    for(int i=x;!isroot(i);i=fa(i))st[++top]=fa(i);
    while(top)push(st[top--]);
    for(;!isroot(x);rotate(x))if(!isroot(fa(x)))
        if(son(x)^son(fa(x)))rotate(x);
        else rotate(fa(x));
}
inline void access(int x){static int h;h=0;while(x)splay(x),ch[x][1]=h,h=x,update(x),x=fa(x);}
inline void rever(int x){access(x),splay(x),rev[x]^=1;}
inline void link(int x,int y){rever(x),fa[x]=y,splay(x);}
inline void cut(int x,int y){rever(x),access(y),splay(y);}

void dfs(int x,int y){
    x=f(x),y=f(y);
    a.merge(x,y);
    if(x!=y)v[y]+=v[x],v[x]=0;
    if(ch[x][0])dfs(ch[x][0],y);
    if(ch[x][1])dfs(ch[x][1],y);
}

int main(void){
    register int i,j,x,y,_x,_y,opt;
    n=read(),m=read();
    for(i=1;i<=n;++i)t[i]=v[i]=sum[i]=read();
    a.init(n),b.init(n);
    while(m--){
        opt=read();
        switch(opt){
            case 1:{
                x=read(),y=read();
                if(f(x)==f(y))break;
                if(b.find(f(x))!=b.find(f(y))){
                    link(f(x),f(y)),b.merge(f(x),f(y));
                }else{
                    rever(f(x));access(f(y));
                    splay(f(y)),
                    dfs(f(y),f(y)),a.merge(f(x),f(y));
                }
                break;
            }
            case 2:{
                x=read(),y=read();
                rever(f(x)),sum[f(x)]+=y-t[x];
                v[f(x)]+=y-t[x];
                t[x]=y;
                break;
            }
            case 3:{
                x=read(),y=read();
                if(b.find(x)!=b.find(y)){
                    puts("-1");
                    break;
                }
                rever(f(x));
                access(f(y));
                splay(f(y));
                printf("%d\n",sum[f(y)]);
                break;
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值