• BZOJ2816:[ZJOI2012]网络——题解


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

    https://www.luogu.org/problemnew/show/P2173

    有一个无向图G,每个点有个权值,每条边有一个颜色。这个无向图满足以下两个条件:

    1. 对于任意节点连出去的边中,相同颜色的边不超过两条。

    2. 图中不存在同色的环,同色的环指相同颜色的边构成的环。

    在这个图上,你要支持以下三种操作:

    1. 修改一个节点的权值。

    2. 修改一条边的颜色。

    3. 查询由颜色c的边构成的图中,所有可能在节点u到节点v之间的简单路径上的节点的权值的最大值。

    这题只要知道什么数据结构,就暴力大模拟即可。

    那显然给你的每种颜色组成的图形是一条链,所以使用LCT。

    然后对每种颜色建LCT即可。

    (纯码农题没有板子情况下1.5h写完1A,这速度怕不是药丸?)

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    using namespace std;
    const int N=1e5+5;
    const int C=11;
    int n,m,c,k,r,fa[C][N],tr[C][N][2],d[C][N];
    int rev[C][N],q[N],key[N],val[C][N],head[N],cnt=-1;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    inline bool get(int x,int w){
        return tr[w][fa[w][x]][1]==x;
    }
    inline bool isroot(int x,int w){
        if(!fa[w][x])return 1;
        return tr[w][fa[w][x]][0]!=x&&tr[w][fa[w][x]][1]!=x;
    }
    inline void pushrev(int x,int w){
        if(!rev[w][x])return;
        swap(tr[w][x][0],tr[w][x][1]);
        if(tr[w][x][0])rev[w][tr[w][x][0]]^=1;
        if(tr[w][x][1])rev[w][tr[w][x][1]]^=1;
        rev[w][x]=0;
    }
    inline void upt(int x,int w){
        val[w][x]=key[x];
        if(tr[w][x][0])val[w][x]=max(val[w][x],val[w][tr[w][x][0]]);
        if(tr[w][x][1])val[w][x]=max(val[w][x],val[w][tr[w][x][1]]);
    }
    inline void rotate(int x,int w){
        int y=fa[w][x],z=fa[w][y],which=get(x,w);
        if(z&&!isroot(y,w))tr[w][z][tr[w][z][1]==y]=x;
        tr[w][y][which]=tr[w][x][which^1];fa[w][tr[w][y][which]]=y;
        fa[w][y]=x;tr[w][x][which^1]=y;fa[w][x]=z;
        upt(y,w);upt(x,w);
    }
    inline void splay(int x,int w){
        q[r=0]=x;
        for(int y=x;!isroot(y,w);y=fa[w][y])q[++r]=fa[w][y];
        for(int i=r;i>=0;i--)pushrev(q[i],w);
        while(!isroot(x,w)){
        if(!isroot(fa[w][x],w))
            rotate(get(x,w)==get(fa[w][x],w)?fa[w][x]:x,w);
        rotate(x,w);
        }
        upt(x,w);
    }
    inline void access(int x,int w){
        for(int y=0;x;y=x,x=fa[w][x]){
        splay(x,w);tr[w][x][1]=y;
        if(y)fa[w][y]=x;
        }
    }
    inline int findroot(int x,int w){
        access(x,w);splay(x,w);
        while(pushrev(x,w),tr[w][x][0])x=tr[w][x][0];
        splay(x,w);
        return x;
    }
    inline void makeroot(int x,int w){
        access(x,w);splay(x,w);
        rev[w][x]^=1;
    }
    inline void split(int x,int y,int w){
        makeroot(x,w);
        access(y,w);splay(y,w);
    }
    inline void link(int x,int y,int w){
        d[w][x]++;d[w][y]++;
        makeroot(x,w);
        fa[w][x]=y;
    }
    inline bool cut(int x,int y,int w){
        split(x,y,w);
        if(tr[w][x][0]||tr[w][x][1]||fa[w][x]!=y||tr[w][y][get(x,w)^1])return 0;
        d[w][x]--;d[w][y]--;
        tr[w][y][0]=0;fa[w][x]=0;
        return 1;
    }
    int main(){
        memset(head,-1,sizeof(head));
        n=read(),m=read(),c=read(),k=read();
        for(int i=1;i<=n;i++)key[i]=read();
        for(int i=1;i<=m;i++){
        int u=read(),v=read(),w=read();
        link(u,v,w);
        }
        for(int i=1;i<=k;i++){
        int op=read();
        if(op==0){
            int x=read(),y=read();
            key[x]=y;
            for(int j=0;j<=c;j++){
            access(x,j);splay(x,j);
            upt(x,j);
            }
        }
        if(op==1){
            int u=read(),v=read(),w=read();
            int ok=-1;
            for(int j=0;j<=c&&ok==-1;j++){
            if(cut(u,v,j))ok=j;
            }
            if(ok==-1){
            puts("No such edge.");
            continue;
            }
            if(d[w][u]>1||d[w][v]>1){
            puts("Error 1.");
            link(u,v,ok);
            continue;
            }
            if(findroot(u,w)==findroot(v,w)){
            puts("Error 2.");
            link(u,v,ok);
            continue;
            }
            puts("Success.");
            link(u,v,w);
        }
        if(op==2){
            int w=read(),u=read(),v=read();
            split(u,v,w);
            if(findroot(u,w)!=findroot(v,w)){
            puts("-1");
            continue;
            }
            split(u,v,w);
            printf("%d
    ",val[w][v]);
        }
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    hdu--4027--不错的线段树
    hdu--3275--线段树<again>
    hdu--2795--又是线段树
    hdu--4407--一不留神就TLE了
    zoj--3822--第二题概率dp
    hdu--3911--线段树<我最近爱上她了>
    hdu--1710--二叉树的各种遍历间的联系
    hdu--1712--分组背包<如果你真的明白了背包..>
    hdu--4576--概率dp<见过最简单的概率dp>
    list remove object
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8694313.html
Copyright © 2020-2023  润新知