bzoj 4736 温暖会指引我们前行

http://www.elijahqi.win/archives/3481
题面http://uoj.ac/problem/274

lct维护最大生成树即可 因为温度互不相同 所以至少大的必须的边都要走 又不可以多走 因为这题字典序的定义比较奇怪 多了反而不好 即lct上维护路径和 维护边的热度最小 然后到时候替换即可

庆幸自己lct还能1A

#include<queue>
#include<cstdio>
#include<cctype>
#include<algorithm>
#define fi first
#define se second
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if(T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
inline void read_s(char *s){
    int op=0;char ch=gc();while(ch<'a'||ch>'z') ch=gc();
    while(ch<='z'&&ch>='a') s[++op]=ch,ch=gc();
}
const int inf=0x3f3f3f3f;
const int N=400030;
int fa1[N],fa[N],c[N][2],size[N],q[N],top,v[N],w[N],X[N],Y[N],n,m,sum[N];
bool rev[N];pa mn[N];char s[N>>2];
inline int find1(int x){
    while(fa1[x]!=x) x=fa1[x]=fa1[fa1[x]];return x;
}
inline void update(int x){
    size[x]=size[c[x][0]]+size[c[x][1]]+1;
    sum[x]=sum[c[x][0]]+sum[c[x][1]]+w[x];
    mn[x]=min(mp(v[x],x),min(mn[c[x][0]],mn[c[x][1]]));
}
inline bool isroot(int x){
    return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
inline void rotate(int x){
    int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
    if (!isroot(y)) c[z][c[z][1]==y]=x;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void pushdown(int x){
    if (rev[x]){
        swap(c[x][0],c[x][1]);rev[c[x][0]]^=1;rev[c[x][1]]^=1;
        rev[x]^=1;
    }
}
inline void splay(int x){
    q[top=1]=x;for (int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
    while(top) pushdown(q[top--]);
    while(!isroot(x)){
        int y=fa[x],z=fa[y];
        if (!isroot(y)){
            if(c[z][0]==y^c[y][0]==x) rotate(x);else rotate(y);
        }rotate(x);
    }
}
inline void access(int x){for (int t=0;x;t=x,x=fa[x]) splay(x),c[x][1]=t,update(x);}
inline void makeroot(int x){access(x);splay(x);rev[x]^=1;}
inline void link(int x,int y){makeroot(x);fa[x]=y;}
inline int split(int x,int y){makeroot(x);access(y);splay(y);}
inline void cut(int x,int y){split(x,y);fa[x]=c[y][0]=0;update(y);}
int main(){
    freopen("bzoj4736.in","r",stdin);
    n=read();m=read();mn[0]=mp(inf,0);
    for (int i=1;i<=n;++i) fa1[i]=i,size[i]=1,mn[i]=mp(inf,i),v[i]=inf;
    for (int i=1;i<=m;++i){
        read_s(s);static int id,x,y,t,l;
        if (s[1]=='f'){
            id=read();x=read();y=read();t=read();l=read();++x;++y;++id;X[id]=x;Y[id]=y;
            sum[id+n]=w[id+n]=l;v[id+n]=t;mn[id+n]=mp(t,id+n);size[id+n]=1;
            if (find1(x)!=find1(y)) link(id+n,y),link(id+n,x),fa1[find1(x)]=y;
            else{int tt;
                split(x,y);
                if(mn[y].fi<t) tt=mn[y].se-n,cut(tt+n,X[tt]),cut(tt+n,Y[tt]),link(id+n,x),link(id+n,y);
            }
        }
        if (s[1]=='m'){
            x=read()+1,y=read()+1;
            if (find1(x)!=find1(y)) {puts("-1");continue;}
            split(x,y);printf("%d\n",sum[y]);   
        }
        if (s[1]=='c'){
            id=read()+1,l=read();
            split(X[id],Y[id]);w[id+n]=l;update(n+id);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值