題意
給一個個點條邊的簡單無向連通圖,要刪掉一些邊,使得度數爲奇數的點儘可能多。輸出長度爲的串,表示刪掉第條邊,表示不刪,要求輸出字典序最大的方案。
分析
比賽結束後幾分鐘調過了這題,錯失了AK的大好機會。
對於兩個能夠互相到達的點,我們可以通過對兩點間某條路徑上邊的狀態取反,來改變這兩個點的奇偶性,所以最後要麼所有點的度數都是奇數,要麼只有一個點的度數是偶數。問題在於如何最大化答案字典序。
如果我們按邊的編號求最大生成樹,每次隨便選兩個度數爲偶數的點,並改變它們樹上路徑中邊的狀態,就能保證編號較小的邊在答案中的狀態必然是。
可以發現在樹的形態固定的條件下,無論按何種方式配對,最終的結果都是一樣的。
這時如果所有點的度數都是奇數,那麼只需要求出所有邊的最終狀態就做完了。
如果有一個點的度數是偶數,則還能改變從這個點開始到任意一個點路徑上邊的狀態。這裏我的做法是以該點爲根dfs求出每條邊到根路徑上第一個編號小於它的邊並在兩者間連邊,從而得到一棵新的樹,然後在新的樹上貪心。
時間複雜度.
代碼
#include<bits/stdc++.h>
#define mp std::make_pair
#define pb push_back
typedef std::pair<int,int> pi;
const int N=600005;
const int M=900005;
int n,m,f[N],h[N],ans[N*2],deg[N],ID[N],FA[N],top,top1,sta[N],sta1[N],dep[N];
std::vector<pi> e[N];
std::vector<int> vec,ee[M];
struct data{int x,y;}a[M];
void dfs(int x,int fa)
{
int id=0;
dep[x]=dep[fa]+1;
for (auto to:e[x])
if (to.first!=fa) dfs(to.first,x),h[x]^=h[to.first];
else id=to.second;
if (h[x]) ans[id]^=1;
FA[x]=fa;ID[x]=id;
}
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
void work(int x,int fa)
{
int id=ID[x],tmp=top1;
if (id)
{
while (top&&sta[top]>id) sta1[++top1]=sta[top--];
ee[sta[top]].pb(id);
sta[++top]=id;
}
for (auto to:e[x])
if (to.first!=fa) work(to.first,x);
if (id) top--;
while (top1>tmp) sta[++top]=sta1[top1--];
}
void dfs1(int x)
{
int mn=m+1;
for (auto to:ee[x])
if (!ans[to]) mn=std::min(mn,to);
if (!x&&mn==m+1) return;
if (mn==m+1)
{
int u=a[x].x,v=a[x].y;
if (dep[v]>dep[u]) u=v;
while (ID[u]) ans[ID[u]]^=1,u=FA[u];
}
else dfs1(mn);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) scanf("%d%d",&a[i].x,&a[i].y),a[i].x++,a[i].y++,ans[i]=1,deg[a[i].x]^=1,deg[a[i].y]^=1;
for (int i=1;i<=n;i++) f[i]=i;
for (int i=m;i>=1;i--)
{
int x=find(a[i].x),y=find(a[i].y);
if (x==y) continue;
f[x]=y;e[a[i].x].pb(mp(a[i].y,i));e[a[i].y].pb(mp(a[i].x,i));
}
for (int i=1;i<=n;i++) if (!deg[i]) vec.pb(i);
for (int j=1;j<vec.size();j+=2) h[vec[j]]^=1,h[vec[j-1]]^=1;
if (vec.size()%2==0) dfs(1,0);
else
{
int rt=vec.back();
dfs(rt,0);
ee[0].clear();
work(rt,0);
dfs1(0);
}
for (int i=1;i<=m;i++) printf("%d",ans[i]);
return 0;
}