时间:2016-03-18 09:55:52 星期五
题目编号:[2016-03-18][POJ][1733][Parity game]
题目大意:给定若干的区间范围内的数字的和,问从哪句开始是错误的
分析:
- 带权并查集
- 区间长度高达1000000000显然不可能直接建立数组,但是发现询问只有5000次,也就是最多出现了5000*2个点,离散化就可以解决问题
- relation[i] i为区间的左端点,fa[i]为区间的右端点,relation[i]维护(i,fa[i])这段区间的和的奇偶状态,0表示偶数,1表示奇数
- f(a,b) f(b,c)表示区间的就状态,那么f(a,c) = (f(a,b) + f(b,c))%2;
#include <map>#include <cstdio>using namespace std;typedef long long LL;#define FOR(x,y,z) for(int (x)=(y);(x)<(z);++(x))const int maxn = 5000*2 + 100;int fa[maxn],relation[maxn];map<LL ,int > m;void ini(){ m.clear(); FOR(i,0,maxn) fa[i] = i;}int fnd(int x){ if(x == fa[x]) return x; int tmp = fa[x]; fa[x] = fnd(fa[x]); relation[x] = (relation[x] + relation[tmp])&1; return fa[x];}int uni(int x,int y,int type){ int fax = fnd(x),fay = fnd(y); if(fax == fay) return 0; fa[fax] = fay; relation[fax] = (relation[x] + relation[y] + type)&1; return 1;}int main(){ //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int len,n,cur = 0,ans = 0,flg = 1; LL u,v; char str[10]; scanf("%d%d",&len,&n); ini(); FOR(i,0,n){ if(flg){ scanf("%I64d%I64d%s",&u,&v,str); --u; if(!m.count(u)) u = m[u] = cur++; else u = m[u]; if(!m.count(v)) v = m[v] = cur++; else v = m[v]; int type = (str[0] == 'o'?1:0); if(!uni(u,v,type)){ int t = (relation[ u ] + relation[ v ])&1; if(t != type){ flg = 0; continue; } } ++ans; }else scanf("%*I64d%*I64d%*s"); } printf("%d\n",ans); return 0;}