zoukankan      html  css  js  c++  java
  • Codeforces 429E(欧拉回路)

    题面

    传送门
    题目大意:
    有n条线段,每条线段染红色或蓝色,使得数轴上每个点被红色线段覆盖的次数与被蓝色线段覆盖数差的绝对值小于等于1。输出染色方案。

    分析

    题意其实可以这样理解:
    一段初始全为0 的序列a,给区间[li,ri]+1或-1,使得操作结束后序列中的所有位置绝对值不超过1
    可采用差分的思想,给al+1,ar+11把区间操作转化成单点操作
    因此我们可以建图来模拟这个过程,从l到r+1连一条边,每个点的值就是入度与出度的差
    建完图后,会出现多个连通块,若联通块是欧拉回路,则区间值为0
    但是,图中会存在许多奇数度的点,必须要连边.
    如果从一个奇点到另一个奇点连一条边,如果区间内还有一个奇点,则该点可能会被一种颜色覆盖多次,导致绝对值大于1
    所以只能将相邻的奇点连边

    总结:
    1.线段右端点+1,离散化
    2.将相邻奇数点连边,跑欧拉回路
    3.输出方案,如果边是从左到右的,输出0,否则输出1

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #define maxn 200005
    using namespace std;
    int n;
    struct seg{
        int l;
        int r;
        int dl;
        int dr;
    }a[maxn];
    int m=0;
    int tmp[maxn<<2];
    int deg[maxn];
    struct edge{
        int from;
        int to;
        int next;
    }E[maxn<<2];
    int size=1;//从1开始存,这样一对反向边会存储在i和i^1的位置
    int head[maxn];
    int dir[maxn<<2];//记录每条边的方向
    int used[maxn];
    void add_edge(int u,int v){
        size++;
        E[size].from=u;
        E[size].to=v;
        E[size].next=head[u];
        head[u]=size;
    }
    
    void dfs(int x){
    //  printf("%d
    ",x);
        used[x]=1;
        for(int i=head[x];i;i=E[i].next){
            if(dir[i>>1]==-1){
                dir[i>>1]=(i&1)^1;//如果i%2==1,则是从左到右的边,dir=0,否则dir=1
                dfs(E[i].to);
            }
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d %d",&a[i].l,&a[i].r);//区间很大,必须离散化
            a[i].r++;
            tmp[++m]=a[i].l;
            tmp[++m]=a[i].r;
        }
        sort(tmp+1,tmp+1+m);
        m=unique(tmp+1,tmp+1+m)-tmp-1;
        for(int i=1;i<=n;i++){
            a[i].dl=lower_bound(tmp+1,tmp+1+m,a[i].l)-tmp;
            a[i].dr=lower_bound(tmp+1,tmp+1+m,a[i].r)-tmp;
            add_edge(a[i].dl,a[i].dr);//连边
            add_edge(a[i].dr,a[i].dl);
            deg[a[i].dl]++;
            deg[a[i].dr]++;
        }
    //  printf("%d
    ",m);
        int pre=0;
        for(int i=1;i<=m;i++){
            if(deg[i]%2&&pre!=0){//相邻的奇数点连边
                add_edge(i,pre);
                add_edge(pre,i);
                pre=0;
            }else if(deg[i]%2){
                pre=i;
            }
        }
        for(int i=1;i<=size/2;i++){
            dir[i]=-1;
        }
        for(int i=1;i<=m;i++){
            if(!used[i]) dfs(i);//欧拉回路
        }
        for(int i=1;i<=n;i++){
            printf("%d ",dir[i]);
        }
    }
  • 相关阅读:
    java-多态
    java-继承
    java-访问修饰符
    mysql基础入门
    子查询
    多表查询
    mysql表(多对多)
    myslql主外键约束
    Sql语句分类
    Redis的一些介绍
  • 原文地址:https://www.cnblogs.com/birchtree/p/9845827.html
Copyright © 2011-2022 走看看