原题链接:
codeforces 840D
大意:
给一个无向连通图,不包含子环,允许回路存在。每个点的权值为
di
,
di
的值为 1 ,-1 ,0 的一种。现在要求构造一个子图,要求每个点的权值为 -1 或是 该点的度数模 2 为
d[i]
。
不存在则输出-1
Limits:
n
<script type="math/tex" id="MathJax-Element-4">n</script> 3e5
思路:
当时比赛的时候有点乱,没理清楚,题目并不难,但是不是很好打。学习了一个写法。
首先考虑特殊情况,
只要有 -1 的点存在,一定存在解,原因在于-1不需要度数要求,每个和-1连的点都可以调整,这个性质可以传递到整个图。
其次当 1 的点为奇数个时,不存在解,这个情况与 不满足的点为奇数个时不存在 等价。
每次剪边都会产生不满足的点+2或是-2 ,利用这个结论可以证明出来。如何得到解
已知可以得到解之后,瞎搞就可以了,注意一点是由于选边会彼此影响,所以需要 dfs序 自底而上处理。
处理技巧是:
预处理 -1 的点,把 -1 的点变为 1 和 0 来互补。
因为每次选边,相当于点权值01的性质变了。
边编号、起点、终点三元组可以通过vector<pair<int,int> > a[MAXN]
实现
if(该边下一个点权值为 1){
该边的两点权值取反;//(1变0,0变1)
选取该边;
}
具体实现:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mem(s,t) memset(s,t,sizeof(s))
#define D(v) cout<<#v<<" "<<v<<endl
#define inf 0x3f3f3f3f
#define pb push_back
#define pii pair<int,int>
//#define LOCAL
const int MAXN =3e5+10;
int n,m;
vector<pii> a[MAXN];
vector<int> ans;
int d[MAXN],de[MAXN],t=0,s=0;
bool vis[MAXN];
void dfs(int x,int y){
vis[x]=1;
for(auto u:a[x]){
if(y==u.first) continue;
if(vis[u.first]) continue;
dfs(u.first,x);
if(d[u.first]){
d[u.first]^=1;
d[x]^=1;
ans.pb(u.second);
}
}
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&d[i]);
if(d[i]==-1) t++;
if(d[i]==1) s++;
}
if(s%2==1&&t==0){
puts("-1");
return 0;
}
for(int i=1;i<=n;i++){
if(d[i]==-1){
d[i]=s%2;
s+=d[i];
}
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
a[x].pb({y,i});
a[y].pb({x,i});
}
dfs(1,0);
sort(ans.begin(),ans.end());
printf("%d\n",ans.size());
for(int i=0;i<ans.size();i++){
printf("%d\n",ans[i]);
}
return 0;
}