1. 程式人生 > >[ZJOI2012]網絡

[ZJOI2012]網絡

ons () 其它 www log upd 表示 影響 沒有

[ZJOI2012]網絡

題目

思路

顯然,這是一道lct裸題。因為顏色不多,所以對於每一種顏色的邊我們都建一個lct即可。(我這裏是用 (顏色×n+點的標號) 表示每一種顏色lct)

操作0

因為我們對於每一種顏色的邊都建了一個lct所以,我們對於每一種顏色的邊都update一次。(雖然很暴力,但跑得過)

操作1

1.其實對於判斷邊不存在的情況,我們可以用臨接矩陣來存,開一個bool數組10000*10000 128M還是開得下的。這樣節約了很多時間(其實是我懶得想其它方法判斷)。

2.錯誤1,開一個degree記錄每個點每一種顏色的邊的度即可。

3.錯誤2,判斷一下兩點在這個顏色的lct是否聯通,若聯通即為不合法的情況,至於怎麽判斷,lct模板。

4.對於可以修改顏色的情況,我們就把原來顏色的邊cut掉,再link新的顏色就可以了。看下面大佬都是用臨接表存邊找顏色,我這裏教你們一招(懶人專用的奇淫技巧)把bool數組開成char數組這樣既可以判斷邊的存在性,又可以判斷邊的顏色,比那些臨接表方便了許多,還節約了時間。(其實對於一些空間不夠的題,可以用short或者char之類的數組來存東西,也許這樣就夠了)

操作2

沒有什麽特殊的地方和其它lct題的查詢沒有什麽區別。

總結

這題lct的部分跟其它題目沒有區別,直接復制粘貼都可以,只是要想到能開多個lct並且這些lct之間互不影響,實現起來還是非常簡單的

代碼

#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
int fa[N],ch[N][2],lazy[N],w[N],ans[N],degree[N],n,m,c;
char pd[10001][10001];
int isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
int get(int x){return ch[fa[x]][1]==x;}
void pushup(int x){ans[x]=max(w[x],max(ans[ch[x][0]],ans[ch[x][1]]));}
void pushdown(int x){
    if(!lazy[x])return;
    swap(ch[x][0],ch[x][1]);
    lazy[ch[x][0]]^=1;
    lazy[ch[x][1]]^=1;
    lazy[x]^=1;
}
void rotate(int x){
    int y=fa[x],z=fa[y],k=get(x);
    fa[x]=z;if(!isroot(y))ch[z][ch[z][1]==y]=x;
    ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y;
    ch[x][k^1]=y;fa[y]=x;
    pushup(y);pushup(x);
}
void push(int x){if(!isroot(x))push(fa[x]);pushdown(x);}
void splay(int x){
    push(x);
    while(!isroot(x)){
        int y=fa[x];
        if(!isroot(y))
            if(get(x)==get(y))rotate(y);
            else rotate(x);
        rotate(x);
    }
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,pushup(x);}
void makeroot(int x){access(x);splay(x);lazy[x]^=1;}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
void cut(int x,int y){split(x,y);fa[x]=ch[y][0]=0;pushup(y);}
int getroot(int x){
    access(x);splay(x);
    while(ch[x][0])x=ch[x][0];
    return x;
}
int query(int x,int y){
    if(getroot(x)!=getroot(y))return -1;
    split(x,y);
    return ans[y];
}
void update(int x,int y){
    makeroot(x);
    w[x]=y;
    pushup(x);
}
void work(int x,int y,int z){
    if(pd[x][y]==0){printf("No such edge.\n");return;}
    int u=x+z*n,v=y+z*n,lu=x+pd[x][y]*n,lv=y+pd[x][y]*n;
    if(pd[x][y]==z){printf("Success.\n");return;}
    if(degree[u]==2||degree[v]==2){printf("Error 1.\n");return;}
    if(getroot(u)==getroot(v)){printf("Error 2.\n");return;}
    degree[lu]--;degree[lv]--;
    degree[u]++;degree[v]++;
    cut(lu,lv);
    link(u,v);
    printf("Success.\n");
    pd[x][y]=z;
    pd[y][x]=z;
}
int main(){
    int k;
    cin>>n>>m>>c>>k;
    for(int i=1;i<=n;++i){
        scanf("%d",&w[i]);ans[i]=w[i];
        for(int j=1;j<=c;++j)
            ans[i+j*n]=w[i+j*n]=w[i];
    }
    for(int i=1;i<=m;++i){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        w++;
        int x=u+w*n,y=v+w*n;
        link(x,y);
        degree[x]++;
        degree[y]++;
        pd[u][v]=w;
        pd[v][u]=w;
    }
    while(k--){
        int op;
        scanf("%d",&op);
        if(op==0){
            int x,y;
            scanf("%d%d",&x,&y);
            for(int i=1;i<=c;++i)
                update(x+i*n,y);
        }
        if(op==1){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);z++;
            work(x,y,z);
        }
        if(op==2){
            int x,y,z;
            scanf("%d%d%d",&z,&x,&y);z++;
            printf("%d\n",query(x+z*n,y+z*n));
        }
    }
    return 0;
}

[ZJOI2012]網絡