P5937 [CEOI1999] Parity Game 题解
DGL__DGL_AFO · · 个人记录
唉唉没人用 2-sat 写的吗。
蒟蒻来水一发 2-sat 的题解。
今天模拟赛的题,赛时想到了 2-sat ,于是写篇题解。
思路:
发现要数
设
于是发现性质:
- 若
l - r 中1 的个数为奇,那么s[r] \oplus s[l-1]=1 ,说明s[r] 和s[l-1] 值不同,反之则说明相同。
因为
因为只有
总时间复杂度为
一些小细节见代码。
代码(赛时写的丑陋代码,用的枚举):
#include<bits/stdc++.h>
using namespace std;
int n,m;
int p[21450],cnt,op;
int l[11450],r[11450],k[11450];
int h[114514],e[214514],ne[214514],idx;
int st[21450],ask[21450];
unordered_map<int,int> un;
string gen;
int flag;
vector<int> v;
inline void add(int a,int b)
{
idx++;
ne[idx]=h[a];
e[idx]=b;
h[a]=idx;
}
inline void dfs(int x)
{
st[x]=1;
ask[x]=1;
if(x<=op)
{
v.push_back(x);
if(ask[x+op])
{
flag=1;
return ;
}
}
if(x>op)
{
v.push_back(x);
if(ask[x-op])
{
flag=1;
return ;
}
}
for(int i=h[x];i;i=ne[i])
{
int y=e[i];
if(!st[y])
dfs(y);
}
}
inline bool check()
{
memset(ask,0,sizeof ask);
memset(st,0,sizeof st);
for(int i=1;i<=op;i++)
{
if(!st[i])
{
flag=0;
dfs(i);
if(flag)
return false;
for(int j=v.size()-1;j>=0;j--)
{
//cout<<v[j]<<" ";
ask[v[j]]--;
v.pop_back();
}
//cout<<"|| ";
}
}
//cout<<'\n';
return true;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>l[i]>>r[i]>>gen;
if(gen[0]=='o')
k[i]=1;
l[i]--;
p[++cnt]=l[i];
p[++cnt]=r[i];
}
sort(p+1,p+1+cnt);
for(int i=1;i<=cnt;i++)
if(!un[p[i]])
un[p[i]]=++op;
for(int i=1;i<=m;i++)
{
int a=un[l[i]],b=un[r[i]];
if(!k[i])
{
add(a,b);
add(b,a);
add(a+op,b+op);
add(b+op,a+op);
}
else
{
add(a,b+op);
add(b+op,a);
add(b,a+op);
add(a+op,b);
}
if(!check())
{
cout<<i-1<<' ';
return 0;
}
}
cout<<m;
return 0;
}
/*
10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd
*/