bzoj 2816: [ZJOI2012]网络 (LCT 建多棵树)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2816

题面: http://www.lydsy.com/JudgeOnline/upload/zjoi2012.pdf

思路:

因为c很小,我们可以建c棵树,然后跑LCT。

 

实现代码:

#include<bits/stdc++.h>
using namespace std;
const int M = 3e5+10;
const int inf = 0x3f3f3f3f;

struct node{
    int u,v;
};
int a[M];
int col[M][11];
bool operator < (node a,node b){
    if(a.u == b.u) return a.v < b.v;
    return a.u < b.u;
}
map<node,int>mp;
struct lct{
int c[M][2],fa[M],val[M],sum[M],rev[M],st[M];
inline void up(int x){
    int l = c[x][0],r = c[x][1];
    sum[x] = max(max(sum[l],sum[r]),val[x]);
}

inline void pushrev(int x){
    int t = c[x][0];
    c[x][0] = c[x][1]; c[x][1] = t;
    rev[x] ^= 1;
}

inline void pushdown(int x){
    if(rev[x]){
        int l = c[x][0],r = c[x][1];
        if(l) pushrev(l);
        if(r) pushrev(r);
        rev[x] = 0;
    }
}

inline bool nroot(int x){  //判断一个点是否为一个splay的根
    return c[fa[x]][0]==x||c[fa[x]][1] == x;
}

inline void rotate(int x){
    int y = fa[x],z = fa[y],k = c[y][1] == x;
    int w = c[x][!k];
    if(nroot(y)) c[z][c[z][1]==y]=x;
    c[x][!k] = y; c[y][k] = w;
    if(w) fa[w] = y; fa[y] = x; fa[x] = z;
    up(y);
}

inline void splay(int x){
    int y = x,z = 0;
    st[++z] = y;
    while(nroot(y)) st[++z] = y = fa[y];
    while(z) pushdown(st[z--]);
    while(nroot(x)){
        y = fa[x];z = fa[y];
        if(nroot(y))
            rotate((c[y][0]==x)^(c[z][0]==y)?x:y);
        rotate(x);
    }
    up(x);
}

//打通根节点到指定节点的实链,使得一条中序遍历从根开始以指定点结束的splay出现
inline void access(int x){
    for(int y = 0;x;y = x,x = fa[x])
        splay(x),c[x][1]=y,up(x);
}

inline void makeroot(int x){  //换根,让指定点成为原树的根
    access(x); splay(x); pushrev(x);
}

inline int findroot(int x){  //寻找x所在原树的树根
    access(x); splay(x);
    while(c[x][0]) pushdown(x),x = c[x][0];
    splay(x);
    return x;
}

inline void split(int x,int y){  //拉出x-y的路径成为一个splay
    makeroot(x); access(y); splay(y);
}

inline void cut(int x,int y){   //断开边
    makeroot(x);
    if(findroot(y) == x&&fa[y] == x&&!c[y][0]){
        fa[y] = c[x][1] = 0;
        up(x);
    }
}

inline void link(int x,int y){   //连接边
    makeroot(x);
    if(findroot(y)!=x) fa[x] = y;
}
}LCT[11];
int main()
{
    int n,m,c,k;
    scanf("%d%d%d%d",&n,&m,&c,&k);
    for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);
    for(int i = 1;i <= n;i ++){
        for(int j = 1;j <= c;j ++){
            LCT[j].val[i] = a[i];
        }
    }
    int u,v,w;
    for(int i = 1;i <= m;i ++){
        scanf("%d%d%d",&u,&v,&w); w++;
        mp[(node){u,v}] = w;
        mp[(node){v,u}] = w;
        col[u][w]++; col[v][w]++;
        LCT[w].link(u,v);
    }
    int op,x,y;
    while(k--){
        scanf("%d",&op);
        if(op == 0){
            scanf("%d%d",&x,&y); a[x] = y;
            for(int i = 1;i <= c;i ++){
                LCT[i].splay(x);
                LCT[i].val[x] = a[x];
            }
        }
        else if(op == 1){
            scanf("%d%d%d",&u,&v,&w); w++;
            int f = mp[(node){u,v}];
            if(!f) {
                printf("No such edge.\n");
                continue;
            }
            if(f == w){
                printf("Success.\n");
                continue;
            }
            if(col[u][w]>1||col[v][w]>1){
                printf("Error 1.\n"); continue;
            }
            if(LCT[w].findroot(u)==LCT[w].findroot(v)){
                printf("Error 2.\n"); continue;
            }
            col[u][f]--; col[v][f]--;
            col[u][w]++; col[v][w]++;
            mp[(node){u,v}] = w;
            mp[(node){v,u}] = w;
            LCT[f].cut(u,v);
            LCT[w].link(u,v);
            printf("Success.\n");
        }
        else{
            scanf("%d%d%d",&w,&u,&v); w++;
            if(LCT[w].findroot(u)!=LCT[w].findroot(v)){
                printf("-1\n"); continue;
            }
            LCT[w].split(u,v);
            printf("%d\n",LCT[w].sum[v]);
        }
    }
}

 

posted @ 2019-04-29 19:15  冥想选手  阅读(172)  评论(0编辑  收藏  举报