題目
正解
似乎曾經某次模擬賽見過?
首先可以發現刪去的邊不存在環,因爲這樣對度數的奇偶性沒有影響。
於是刪去的邊形成一個森林。
先講的部分分:
隨便找某個節點作爲根,然後從葉子節點往上做。對於每個點,可以通過它的父親邊選或不選使得它的度數保持爲奇數。對於根節點,可以計算出它最終的度數也是奇數。
然後發現不管以哪個點作爲根的時候,方案都是唯一的。
還有一種優秀的理解方法:
建出樹之後,找到兩個度數爲偶數的節點,將它們路徑上的邊的狀態都取反。容易發現中間的點的度數奇偶性不變,這兩個節點的度數都變成了奇數。
只要偶數個數爲偶數,這樣操作若干次之後,全部點都會是奇數度數。
然後就是的部分分:
爲了使得字典序最小,考慮從後往前生成樹。不在生成樹中的邊都欽定它們保留。
然後直接在這個生成樹上操作。方案唯一,所以是對的。
但是當爲奇數的時候,這個方法就會有鍋。因爲在生成樹之後,選取的根不同會生成不同的答案。
接下來考慮按順序欽定每條邊選或不選:
對於最小的邊,求出它連的兩個連通塊中偶數點個數的奇偶性。
如果都是奇數,則這條邊必須被刪;否則這條邊被保留。
接下來不需要考慮這條邊,然後變成了兩個子問題,遞歸下去考慮。
具體實現可以從後往前建出重構樹,然後用樹狀數組維護子樹中偶數點的奇偶性。
代碼
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 600010
#define M 900010
int n,m,cnt;
struct edge{
int u,v;
} ed[M];
int deg[N];
int dsu[N*2];
int getdsu(int x){return dsu[x]==x?x:dsu[x]=getdsu(dsu[x]);}
int to[N*2][2];
int ide[N*2];
int nowdfn,in[N*2],out[N*2];
int t[N];
void xo(int x,int c){
for (;x<=n;x+=x&-x)
t[x]^=c;
}
int query(int x){
int r=0;
for (;x;x-=x&-x)
r^=t[x];
return r;
}
void init(int x){
if (x<=n){
in[x]=out[x]=++nowdfn;
return;
}
init(to[x][0]);
init(to[x][1]);
in[x]=in[to[x][0]];
out[x]=out[to[x][1]];
}
int getxor(int x){
return query(out[x])^query(in[x]-1);
}
int ans[M];
void dfs(int x){
if (x<=n)
return;
if (getxor(to[x][0]) && getxor(to[x][1])){
int u=ed[ide[x]].u,v=ed[ide[x]].v;
deg[u]^=1,xo(in[u],1);
deg[v]^=1,xo(in[v],1);
ans[ide[x]]=0;
}
else
ans[ide[x]]=1;
dfs(to[x][0]);
dfs(to[x][1]);
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;++i){
scanf("%d%d",&ed[i].u,&ed[i].v);
deg[ed[i].u]^=1;
deg[ed[i].v]^=1;
}
for (int i=1;i<=n;++i)
dsu[i]=i;
cnt=n;
for (int i=m;i>=1;--i){
int x=getdsu(ed[i].u),y=getdsu(ed[i].v);
// printf("%d %d\n",x,y);
if (x==y)
ans[i]=1;
else{
++cnt;
ide[cnt]=i;
dsu[cnt]=cnt;
dsu[x]=dsu[y]=cnt;
to[cnt][0]=x;
to[cnt][1]=y;
// printf("%d:%d %d\n",cnt,x,y);
}
}
int rt=cnt;
init(rt);
for (int i=1;i<=n;++i)
if (deg[i]==0)
xo(in[i],1);
dfs(rt);
for (int i=1;i<=m;++i)
putchar(ans[i]+'0');
return 0;
}