zoukankan      html  css  js  c++  java
  • POI[2011]Garbage 欧拉回路的正确姿势

    题目大意是讲给定一张图,每跳边有编号$0$或$1$,每次可以将一个简单环上所有边$oplus 1$,构造方案使得每跳边的编号是某个值,方案中涉及的边不超过5m

    如果方案中的两个环有相交部分,相交部分没有变化,去掉之后2个环合并成了一个环。所以存在一种方案使得所有环都不相交

    于是删除需要进过偶数次的边,对每个联通块求欧拉回路(不是道路),然后再用栈搞一搞弄出所有的环,时间复杂度$O(n + m)$

    TLE...,为了卡常数还怒写人工栈...然后发现欧拉回路部分,一开始我是这么写的

    void dfs(int u)
    {
        vis[u] = 1;
        for (int i = head[u], v; v = e[i].node, i; i = e[i].next)
            if (!flag[i])
            {
                flag[i] = flag[i ^ 1] = 1;
                dfs(v);
                mem[++mem[0]] = i;
            }
    }

    一直都以为这样写就是对的,然后发现自己太naive了,每个点都从头开始找没有被标记过的边,复杂度是能退化的。。

    正确的姿势应该是记录每个点最后一条标记的边是哪一条,然后从那一条边开始继续扫描(人工栈版本)

    void dfs(int rt)
    {
        S[top = 1].u = rt, S[1].i = head[rt], S[1].t = 0;
        while (top)
        {
            int u = S[top].u, i = S[top].i, tmp = top; S[top].t++; 
            if (S[top].t == 2) {mem[++mem[0]] = i; S[top].t = 1;}
            i = cur[u];
            vis[u] = 1;
            for (int v; v = e[i].node, i; i = e[i].next)
            if (!flag[i])
            {
                flag[i] = flag[i ^ 1] = 1;
                S[++top].u = v; S[top].i = cur[v]; 
                S[top].t = 0; S[tmp].i = i; cur[u] = i;
                break;
            }
            if (tmp == top) top--;
        }
    }
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cmath>
      4 #include <cstring>
      5 #include <algorithm>
      6 #include <vector>
      7 #include <ctime>
      8 using namespace std;
      9 #define rep(i, l, r) for (int i = l; i <= r; i++)
     10 #define drep(i, r, l) for (int i = r; i >= l; i--)
     11 typedef long long ll;
     12 const int N = 1e5 + 8, M = 1e6 + 8;
     13 int n, m, tot, head[N], mem[M << 1], top, sz, cnt[N], q[M << 1], deg[N], vis[N], cur[N];
     14 bool flag[M << 1];
     15 int ans[M * 5], len, sta[M];
     16 int xgw;
     17 //double t1, t2;
     18 int getint()
     19 {
     20     char c; int num = 0, w = 1;
     21     for (c = getchar(); !isdigit(c) && c != '-'; c = getchar());
     22     if (c == '-') c = getchar(), w = -1;
     23     for (;isdigit(c); c = getchar()) num = num * 10 + c - '0';
     24     return num * w;
     25 }
     26 struct Edge{int next, node;}e[M << 1];
     27 inline void add(int x, int y)
     28 {
     29     e[++tot].next = head[x], head[x] = tot, e[tot].node = y;
     30     e[++tot].next = head[y], head[y] = tot, e[tot].node = x;
     31 }
     32 struct RGZ
     33 {
     34     int u, i, t;
     35 }S[M];
     36 void dfs(int rt)
     37 {
     38     S[top = 1].u = rt, S[1].i = head[rt], S[1].t = 0;
     39     while (top)
     40     {
     41         int u = S[top].u, i = S[top].i, tmp = top; S[top].t++; 
     42         if (S[top].t == 2) {mem[++mem[0]] = i; S[top].t = 1;}
     43         i = cur[u];
     44         vis[u] = 1;
     45         for (int v; v = e[i].node, i; i = e[i].next)
     46         if (!flag[i])
     47         {
     48             flag[i] = flag[i ^ 1] = 1;
     49             S[++top].u = v; S[top].i = cur[v]; 
     50             S[top].t = 0; S[tmp].i = i; cur[u] = i;
     51             break;
     52         }
     53         if (tmp == top) top--;
     54     }
     55 }
     56 inline bool calc(int rt)
     57 {
     58     mem[0] = 0; top = 0;
     59     dfs(rt);
     60     if (!mem[0]) return 1;
     61     q[top = 1] = e[mem[mem[0]] ^ 1].node; cnt[q[1]]++;
     62     drep(i, mem[0], 1)
     63     {
     64         int u = e[mem[i]].node;
     65         cnt[u]++; 
     66         if (cnt[u] == 2)
     67         {
     68             ++sz; ans[++len] = u; sta[sz] = len;
     69             while (cnt[u] > 1)
     70                 ans[++len] = q[top], cnt[q[top]]--, top--;
     71         }
     72         q[++top] = u;
     73     }
     74     if (top > 1) return 0;
     75 }
     76 void solve()
     77 {
     78     rep(i, 1, n) 
     79     if (deg[i] & 1)
     80     {
     81         printf("NIE
    ");
     82         return;
     83     }
     84     rep(i, 1, n) cur[i] = head[i];
     85     rep(i, 1, n) 
     86         if (deg[i] && !vis[i]) 
     87             if (!calc(i))
     88             {
     89                 printf("NIE
    ");
     90                 return;
     91             }
     92     printf("%d
    ", sz); sta[sz + 1] = len + 1;
     93     rep(i, 1, sz)
     94     {
     95         printf("%d ", sta[i + 1] - sta[i] - 1);
     96         rep(j, sta[i], sta[i + 1] - 1) printf("%d ", ans[j]);
     97         putchar('
    ');
     98     }
     99 }
    100 int main()
    101 {
    102     //freopen("input.txt","r",stdin);
    103     //freopen("output.txt","w",stdout);
    104     scanf("%d%d", &n, &m); tot = 1;
    105     rep(i, 1, m)
    106     {
    107         int u = getint(), v = getint(), x = getint(), y = getint();
    108         if (y != x) add(u, v), deg[u]++, deg[v]++;
    109     }
    110     solve();
    111     //fclose(stdin); fclose(stdout);
    112     return 0;
    113 }
    POI2011Garbage
    
    
    
     
  • 相关阅读:
    c#截取后几位
    GridView里嵌套RadioButton单选
    sql存储过程无重复添加修改
    Javascript指令
    多级联动Dropdownlist(刷新版)
    docker部署redis问题解决
    docker 安装 gitlab
    docker安装jenkins
    部分ansible常用模块
    ansible
  • 原文地址:https://www.cnblogs.com/Dyzerjet/p/4471523.html
Copyright © 2011-2022 走看看