1. 程式人生 > >BZOJ 2594: [Wc2006]水管局長數據加強版(lct)

BZOJ 2594: [Wc2006]水管局長數據加強版(lct)

-- for 維護 int void rotate roo ESS sin

傳送門

解題思路

  一道\(lct\)維護動態最小生成樹。剛開始寫了一遍瘋狂\(Re\),冷靜了一下重新寫了一遍終於過了。首先題目中要求兩點之間最大值的最小值,其實就是維護一個最小生成樹,每次詢問最大值。要將刪邊轉化成加邊操作,就是倒著處理,這裏用\(set\)\(map\)就比較方便。然後還要把邊權轉化成點權,具體來說就是假如\(x,y\)直接有一條權值為\(z\)的邊,那麽就新開一個節點,令這個點的權值為\(z\),然後連接\(x\)與這個節點,\(y\)與這個節點。\(lct\)裏維護一下最大值的節點的編號。每當假如一條邊時要判斷一下這條路徑的最大值是否大於新加入的邊,大於的話就先\(cut\)

掉最大值,然後再\(link\)

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<map>
#include<set>

using namespace std;
const int MAXN = 100005;
const int MAXM = 1000005;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch==‘-‘?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
    return f?x:-x;
} 

int n,m,q,num,fa[MAXN+MAXM],ch[MAXN+MAXM][2],Max[MAXN+MAXM];
int F[MAXN],val[MAXN+MAXM],tot,xx[MAXN+MAXM],yy[MAXN+MAXM];
int cnt,ans[MAXN];
bool tag[MAXN+MAXM];
map<pair<int,int>,int > mp;
set<pair<int,int> > S;

struct Edge{
    int x,y,z,id;
    friend bool operator<(const Edge A,const Edge B){
        return A.z<B.z;
    }
}edge[MAXM];

struct Query{
    int x,y,type,id;
}ask[MAXN];

int Find(int x){
    if(x==F[x]) return x;
    return F[x]=Find(F[x]);
}

inline bool check(int x){
    return (x==ch[fa[x]][1]);
}

inline bool isroot(int x){
    return (x!=ch[fa[x]][0] && x!=ch[fa[x]][1]);
}

inline void pushup(int x){
    Max[x]=x;
    if(val[Max[ch[x][0]]]>val[Max[x]]) Max[x]=Max[ch[x][0]];
    if(val[Max[ch[x][1]]]>val[Max[x]]) Max[x]=Max[ch[x][1]];
}

inline void pushdown(int x){
    if(tag[x]){
        tag[x]=0;swap(ch[x][0],ch[x][1]);
        if(ch[x][0]) tag[ch[x][0]]^=1;
        if(ch[x][1]) tag[ch[x][1]]^=1;
    }
}

void pd(int x){
    if(!isroot(x)) pd(fa[x]);pushdown(x);
}

inline void rotate(int x){
    int y=fa[x],z=fa[y];bool chk=check(x);
    if(!isroot(y)) ch[z][check(y)]=x;
    ch[y][chk]=ch[x][chk^1];fa[ch[x][chk^1]]=y;
    ch[x][chk^1]=y;fa[y]=x;fa[x]=z;pushup(y);pushup(x);
}

inline void splay(int x){
    pd(x);
    for(;!isroot(x);rotate(x))
        if(!isroot(fa[x])) rotate(check(fa[x])==check(x)?fa[x]:x);
}

inline void access(int x){
    for(int y=0;x;y=x,x=fa[x]){
        splay(x);ch[x][1]=y;pushup(x);
    }
}

inline void makeroot(int x){
    access(x);splay(x);tag[x]^=1;
}

inline void link(int x,int y){
    makeroot(x);fa[x]=y;pushup(y);
}

inline void cut(int x,int y){
    makeroot(x);access(y);splay(y);
    ch[y][0]=fa[x]=0;pushup(y);
}

inline void split(int x,int y){
    makeroot(x);access(y);splay(x);
}

int main(){
    n=rd(),m=rd(),q=rd();int x,y,z;num=n;
    for(int i=1;i<=n;i++) F[i]=i;
    for(int i=1;i<=m;i++) {
        x=rd(),y=rd(),z=rd();if(x>y) swap(x,y);
        edge[i].x=x,edge[i].y=y,edge[i].z=z;
        mp[make_pair(x,y)]=z;
    }
    for(int i=1;i<=q;i++){
        z=rd(),x=rd(),y=rd();if(x>y) swap(x,y);
        if(z==2) S.insert(make_pair(x,y));
        ask[i].type=z;ask[i].x=x;ask[i].y=y;
    }
    sort(edge+1,edge+1+m);int u,v;
    for(int i=1;i<=m;i++){
        x=edge[i].x,y=edge[i].y;
        if(S.find(make_pair(x,y))!=S.end()) continue;
        u=Find(x);v=Find(y);if(u==v) continue;
        F[u]=v;val[++num]=edge[i].z;link(x,num);link(num,y);
        xx[num]=x;yy[num]=y;tot++;if(tot==n-1) break;
    }int x1,x2;
    for(int i=q;i;i--){
        x=ask[i].x;y=ask[i].y;
        if(ask[i].type==1) {split(x,y);ans[++cnt]=val[Max[x]];}
        else{
            val[++num]=mp[make_pair(x,y)];
            split(x,y);if(val[Max[x]]<=val[num]) continue;
            x1=xx[Max[x]];x2=Max[x]; //!!!註意這裏要把值拿出來,否則第一個$cut$的時候有可能改變這裏的值。
            cut(xx[Max[x]],Max[x]);cut(x2,x1);
            link(x,num);link(num,y);xx[num]=x;yy[num]=y;
        }
    }
    for(int i=cnt;i;i--) printf("%d\n",ans[i]);
    return 0;
}

BZOJ 2594: [Wc2006]水管局長數據加強版(lct)