【POI2011】Garbage

题面

https://loj.ac/problem/2162

题解

水题,首先同样的边只需要一条,如果一条边在一个回路里出现了两次,直接删去,同样是满足判定的。

直接欧拉回路。

#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100050
#define ri register int
using namespace std;

int n,m,u,v,ms,mt,f[N],vis[N];
stack<int> s;
int cur[N],deg[N];
vector<int> ed[N],vv,to;

inline int read() {
  int ret=0,f=0; char ch=getchar();
  while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
  while (ch>='0' && ch<='9') ret*=10,ret+=(ch-'0'),ch=getchar();
  return f?-ret:ret;
}

int getf(int x) {
  if (x==f[x]) return x;
  return f[x]=getf(f[x]);
}

void add_edge(int u,int v) {
  f[getf(u)]=getf(v);
  to.push_back(v); vv.push_back(0); ed[u].push_back(to.size()-1);
  to.push_back(u); vv.push_back(0); ed[v].push_back(to.size()-1);
  deg[u]++; deg[v]++;
}

void euler1(int x) {
  for (ri &i=cur[x];i<ed[x].size();i++) {
    int e=ed[x][i];
    if (vv[e]) continue;
    vv[e]=vv[1^e]=1;
    euler1(to[e]);
    s.push(to[e]);
  }
}

int main(){
  n=read(); m=read();
  for (ri i=1;i<=n;i++) f[i]=i;
  for (ri i=1;i<=m;i++) {
    u=read(),v=read(),ms=read(),mt=read();
    if (ms!=mt) add_edge(u,v);
  }
  for (ri i=1;i<=n;i++) if (deg[i]&1) {
    puts("NIE");
    return 0;
  }
  int ans=0;
  for (ri i=1;i<=n;i++) if (i!=getf(i)) {
    if (!vis[getf(i)]) ans++;
    vis[getf(i)]=1;
  }
  printf("%d\n",ans);
  for (ri i=1;i<=n;i++) {
    if (vis[getf(i)]==2 || vis[getf(i)]==0) continue;
    vis[getf(i)]=2;
    euler1(i);
    printf("%d ",s.size());
    printf("%d ",i);
    while (!s.empty()) printf("%d ",s.top()),s.pop();
    puts("");
  }
  return 0;
}

 

posted @ 2019-08-14 08:33  HellPix  阅读(114)  评论(0编辑  收藏  举报