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\n");
 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\n");
 90                 return;
 91             }
 92     printf("%d\n", 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('\n');
 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

 

 
posted on 2015-05-02 08:32  Dyzerjet  阅读(390)  评论(0编辑  收藏  举报