CF1610F Mashtali: a Space Oddysey
Description
给定一张含 \(n\) 个点 \(m\) 条边的无向图,结点编号为 \(1\) 到 \(n\)。
每条边有边权 \(w_i\),而 \(w_i\) 只能等于 \(1\) 或 \(2\)。蓝想要给每条边定向,使得图尽可能的可爱。
图的可爱程度定义为图中好的结点的数量。一个结点 \(v\) 是好的,当且仅当令 \(d^+(v)\) 为 \(v\) 所有出边的权值和,令 \(d^-(v)\) 为 \(v\) 所有入边的权值和,有 \(|d^+(x)-d^-(x)|=1\)。
试着帮蓝找到图的最大可能可爱程度,并且给出任意一种构造方案。
本题数据满足:\(1 \leq n,m \leq 3\times10^5,1 \leq u_i,v_i \leq n,\mathbf{w_i\in\{1,2\}}\)
Solution
先考虑问题的简化版:所有的 \(w_i=1\)。
首先答案有一个上界:度数为奇数的点的个数。现在我们试图让答案达到这个上界。
建立超级源点 \(T\),如果点 \(v\) 的度数为奇数,则新建一条无向边 \((v,T)\)。
现在所有节点的度数都是偶数。在新图上跑出一条欧拉回路,回路上经过这条边的方向就是答案中边的方向。
在欧拉回路中,每一个点都被进出相同次。对于一条边 \((v,T)\),如果经过的方向是 \(v \rightarrow T\),那么在原图中就对应 \(d^+(v)-d^-(v)=1\);反之则对应 \(d^-(v)-d^+(v)=1\)。
再回到原问题。考虑将图拆为两部分,一部分只包含 \(w_i=1\) 的边,另一部分只包含 \(w_i=2\) 的边,对每一部分用上述方法跑欧拉回路。但我们只能让 \(|d^+(x)-d^-(x)|\) 为奇数的点最大化,无法保证 \(|d^+(x)-d^-(x)|=1\) 个数最大化。
问题出在两个部分不能完全独立。令 \(F(x),S(x)\) 分别表示 \(x\) 在第一、第二部分中对应的点,\(d1(x),d2(x)\) 分别表示 \(x\) 这个点在第一、第二部分中对应点的度数,我们在尝试构造一张新图:
- 若 \(w(u,v)=1\),则建边 \((F(u),F(v))\);
- 若 \(w(u,v)=2\),则建边 \((S(u),S(v))\);
- 若 \(d1(x),d2(x)\) 均为奇数,则建边 \((F(x),S(x))\);
- 若只有 \(d1(x)\) 为奇数,则建边 \((T,F(x))\);
- 若只有 \(d2(x)\) 为奇数,则建边 \((T,S(x))\)。
新图仍然满足所有节点的度数是偶数,但新图的欧拉回路就可以成为答案。
设 \(V(x)=d^+(x)-d^-(x)\)。
对于一个满足条件 \(3\) 的节点,若欧拉回路中方向为 \(F(x) \rightarrow S(x)\),那么对应原图中 \(V(F(x))=1,V(S(x))=-2\),则有 \(V(x)=-1\)。反之则有 \(V(x)=1\)。
对于一个满足条件 \(4\) 的节点,分析同上。对于一个满足条件 \(5\) 的节点,其一定不会成为好点。
那么我们的欧拉回路使得所有邻边权值和为奇数的点都成为了好点。
int n,m,T;
int head[N],tot,d1[N],d2[N],ans[N<<1];
bool vis[N],usd[N<<1];#define F(x) x
#define S(x) x+nstruct Edge{int v,id,tp;
};
vector<Edge> e[N];void Add(int u,int v,int w){e[u].push_back({v,w,1});e[v].push_back({u,w,2});
}void dfs(int x){vis[x]=1;for(int i=head[x];i<(signed)e[x].size();i=head[x]){head[x]=i+1;if(usd[e[x][i].id]) continue;usd[e[x][i].id]=1;ans[e[x][i].id]=e[x][i].tp;dfs(e[x][i].v);}
}signed main(){read(n),read(m);for(int i=1;i<=m;i++){int u,v,w;read(u),read(v),read(w);if(w==1){Add(F(u),F(v),i);d1[u]++,d1[v]++;}else{Add(S(u),S(v),i);d2[u]++,d2[v]++;}}int cnt=m,Ans=0; T=2*n+1;for(int i=1;i<=n;i++){if((d1[i]&1)&&(d2[i]&1)) Add(F(i),S(i),++cnt);else if(d1[i]&1) Add(T,F(i),++cnt);else if(d2[i]&1) Add(T,S(i),++cnt);int cd=d1[i]+d2[i]*2;if(cd&1) Ans++;}for(int i=1;i<=T;i++){if(!vis[i]){dfs(i);}}printf("%d\n",Ans);for(int i=1;i<=m;i++) putchar(ans[i]+'0');puts("");return 0;
}