zoukankan      html  css  js  c++  java
  • BZOJ2816: [ZJOI2012]网络

    BZOJ2816: [ZJOI2012]网络

    BZOJ题面

    题目描述

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

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

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

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

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

    2. 修改一条边的颜色。

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

    输入输出格式

    输入格式:

    输入文件network.in的第一行包含四个正整数N, M, C, K,其中N为节点个数,M为边数,C为边的颜色数,K为操作数。

    接下来N行,每行一个正整数vi,为节点i的权值。

    之后M行,每行三个正整数u, v, w,为一条连接节点u和节点v的边,颜色为w。满足1 ≤ u, v ≤ N,0 ≤ w < C,保证u ≠ v,且任意两个节点之间最多存在一条边(无论颜色)。

    最后K行,每行表示一个操作。每行的第一个整数k表示操作类型。

    1. k = 0为修改节点权值操作,之后两个正整数x和y,表示将节点x的权值vx修改为y。

    2. k = 1为修改边的颜色操作,之后三个正整数u, v和w,表示将连接节点u和节点v的边的颜色修改为颜色w。满足0 ≤ w < C。

    3. k = 2为查询操作,之后三个正整数c, u和v,表示查询所有可能在节点u到节点v之间的由颜色c构成的简单路径上的节点的权值的最大值。如果不存在u和v之间不存在由颜色c构成的路径,那么输出“-1”。

    输出格式:

    输出文件network.out包含若干行,每行输出一个对应的信息。

    1. 对于修改节点权值操作,不需要输出信息。

    2. 对于修改边的颜色操作,按以下几类输出:

    a) 若不存在连接节点u和节点v的边,输出“No such edge.”。

    b) 若修改后不满足条件1,不修改边的颜色,并输出“Error 1.”。

    c) 若修改后不满足条件2,不修改边的颜色,并输出“Error 2.”。

    d) 其他情况,成功修改边的颜色,并输出“Success.”。

    输出满足条件的第一条信息即可,即若同时满足b和c,则只需要输出“Error 1.”。

    1. 对于查询操作,直接输出一个整数。

    输入输出样例

    输入样例#1: 复制
    4 5 2 7
    1
    2
    3
    4
    1 2 0
    1 3 1
    2 3 0
    2 4 1
    3 4 0
    2 0 1 4
    1 1 2 1
    1 4 3 1
    2 0 1 4
    1 2 3 1
    0 2 5
    2 1 1 4
    输出样例#1: 复制
    4
    Success.
    Error 2.
    -1
    Error 1.
    5

    说明

    颜色0为实线的边,颜色1为虚线的边,

    由颜色0构成的从节点1到节点4的路径有1 – 2 – 4,故max{v1, v2, v4} = max{ 1, 2, 4 } = 4。

    将连接节点1和节点2的边修改为颜色1,修改成功,输出“Success.”

    将连接节点4和节点3的边修改为颜色1,由于修改后会使得存在由颜色1构成的环( 1 – 2 – 4 – 3 – 1 ),不满足条件2,故不修改,并输出“Error 2”。

    不存在颜色0构成的从节点1到节点4的边,输出“-1”。

    将连接节点2和节点3的边修改为颜色1,由于修改后节点2的连出去的颜色为1的边有3条,故不满足条件1,故不修改,并输出“Error 1.”。

    将节点2的权值修改为5。

    由颜色1构成的从节点1到节点4的路径有 1 – 2 – 4,故max{v1, v2, v4} = max{ 1, 5, 4 } = 5。

    【数据规模】

    对于30%的数据:N ≤ 1000,M ≤ 10000,C ≤ 10,K ≤ 1000。

    另有20%的数据:N ≤ 10000,M ≤ 100000,C = 1,K ≤ 100000。

    对于100%的数据:N ≤ 10000,M ≤ 100000,C ≤ 10,K ≤ 100000。

    注:题面复制于洛谷。


    题解Here!

    我本来一看到颜色数,$woc$,又一道置换群的题,吓得不敢做。。。

    直到今天我补完了$Polya$定理的最后一点内容,回头来看这题。

    心想这下会做了吧。。。

    然后这个$flag$在$3s$之后被推翻了。。。

    这$TM$不是$LCT$的沙茶题么???

    感觉自己就是个沙茶。。。

    根据题目,我们可以发现我们要维护几条链,还要断来断去,连来连去的。。。

    当然$LCT$!

    注意到颜色数最多只有$10$中,所以直接开$10$颗$LCT$就好辣!

    操作$0$好做,直接暴力对每个颜色的链中的$x$修改就好。

    操作$2$也好做,用$findroot(x)$判连通,直接查询就好。

    这两个是$LCT$基本操作了。

    来看操作$1$。

    我直接用$STL$里的$map$来求$u,v$之间的边的颜色。

    注意我的颜色数为了方便,是$[1,c]$的。

    $STL$大法好!

    如果颜色为$0$,或者$u==v$(题目活坑。。。),说明没有边,直接输出$No such edge.$(有句点!)

    对于限制$1$,我们对于每个颜色开一个$degree[x]$记录$x$连接的边有多少条,然后大力特判就好。

    对于限制$2$,用$findroot(x)$判断连通即可。

    其他情况就先$cut(u,v)$,再$link(u,v)$即可。不要忘了维护$degree[x]$哦!

    记得特判新的边的颜色是否和原来的颜色相同,这种情况直接输出$Success.$。

    然后就是一大堆细节问题了,这个只能看代码,我也没有辨法啊。。。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<map>
    #define MAXN 10010
    using namespace std;
    map<int,int> colour[MAXN];
    int n,m,c,q;
    int val[MAXN];
    int top=0,stack[MAXN];
    inline int read(){
        int date=0,w=1;char c=0;
        while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
        while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
        return date*w;
    }
    struct LCT{
        int degree[MAXN];
        struct Link_Cut_Tree{
            int son[2];
            int f,v,flag;
        }a[MAXN];
        inline bool isroot(int rt){
            return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt;
        }
        inline void pushup(int rt){
            if(!rt)return;
            a[rt].v=max(val[rt],max(a[a[rt].son[0]].v,a[a[rt].son[1]].v));
        }
        inline void pushdown(int rt){
            if(!rt||!a[rt].flag)return;
            a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag^=1;
            swap(a[rt].son[0],a[rt].son[1]);
        }
        inline void turn(int rt){
            int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0;
            if(!isroot(x)){
                if(a[y].son[0]==x)a[y].son[0]=rt;
                else a[y].son[1]=rt;
            }
            a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x;
            a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x;
            pushup(x);pushup(rt);
        }
        void splay(int rt){
            top=0;
            stack[++top]=rt;
            for(int i=rt;!isroot(i);i=a[i].f)stack[++top]=a[i].f;
            while(top)pushdown(stack[top--]);
            while(!isroot(rt)){
                int x=a[rt].f,y=a[x].f;
                if(!isroot(x)){
                    if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt);
                    else turn(x);
                }
                turn(rt);
            }
        }
        inline void access(int rt){
            for(int i=0;rt;i=rt,rt=a[rt].f){
                splay(rt);
                a[rt].son[1]=i;
                pushup(rt);
            }
        }
        inline void makeroot(int rt){access(rt);splay(rt);a[rt].flag^=1;}
        int findroot(int rt){
            access(rt);splay(rt);
            while(a[rt].son[0])rt=a[rt].son[0];
            return rt;
        }
        inline void split(int x,int y){makeroot(x);access(y);splay(y);}
        inline void link(int x,int y){makeroot(x);a[x].f=y;}
        inline void cut(int x,int y){
            split(x,y);
            if(a[y].son[0]==x&&a[x].f==y&&!a[x].son[1])a[x].f=a[y].son[0]=0;
        }
        inline void update(int rt,int k){access(rt);splay(rt);val[rt]=k;pushup(rt);}
        inline int query(int x,int y){split(x,y);return a[y].v;}
        inline bool check(int x,int y){
            if(findroot(x)!=findroot(y))return false;
            return true;
        }
    }tree[11];
    void work(){
        int f,x,y,k;
        while(q--){
            f=read();
            if(f==0){
                x=read();k=read();
                for(int i=1;i<=c;i++)tree[i].update(x,k);
            }
            else if(f==1){
                x=read();y=read();k=read()+1;
                int w=colour[x][y];
                if(w==k)printf("Success.
    ");
                else if(!w||x==y)printf("No such edge.
    ");
                else if(tree[k].degree[x]==2||tree[k].degree[y]==2)printf("Error 1.
    ");
                else if(tree[k].check(x,y))printf("Error 2.
    ");
                else{
                    colour[x][y]=k;
                    tree[w].cut(x,y);
                    tree[w].degree[x]--;tree[w].degree[y]--;
                    tree[k].link(x,y);
                    tree[k].degree[x]++;tree[k].degree[y]++;
                    printf("Success.
    ");
                }
            }
            else{
                k=read()+1;x=read();y=read();
                if(!tree[k].check(x,y))printf("-1
    ");
                else printf("%d
    ",tree[k].query(x,y));
            }
        }
    }
    void init(){
        int u,v,w;
        n=read();m=read();c=read();q=read();
        for(int i=1;i<=n;i++)val[i]=read();
        for(int i=1;i<=m;i++){
            u=read();v=read();w=read()+1;
            colour[u][v]=colour[v][u]=w;
            tree[w].degree[u]++;tree[w].degree[v]++;
            tree[w].link(u,v);
        }
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    Java Json 数据下划线与驼峰格式进行相互转换
    Java反射常用示例
    ApplicationContextAware 快速获取bean
    Spring AOP自动代理创建者
    Spring依赖检查
    Bean作用域实例
    注入值到Spring bean属性
    用javaConfig 代替 xml 配置
    spring使用@Autowired装载
    Spring 概述
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9495955.html
Copyright © 2011-2022 走看看