poj1733 parity game---离散化+带权并查集

题目链接:https://vjudge.net/problem/POJ-1733

题意:给定一个01序列,对于每个给出的区间,回答一个区间内1的个数为奇数还是偶数。求在第几条回答时出现矛盾

设v[x]=0/1表示x与par[x]组成的区间有偶数/奇数个1,之后利用异或的性质使用带权并查集即可,具体就是加减的奇偶性和异或相对应(由此可发现只能设v[x]=0表示偶数)。序列可能很长,但是询问只有5000个,所以需要离散化,这儿偷懒用了map。另外还有一个小技巧之前用过,就是将左边区间变成开区间,这个在hdu3038中也用到了

#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;

const int maxn=10000;
int t,n,q,i,cnt,f,ans;
int par[maxn+10],v[maxn+10];
map<int,int> c;

int find(int x){
	if (par[x]!=x){
	  int u=par[x];
	  par[x]=find(par[x]);
	  v[x]^=v[u]; //*	  
	}
	return par[x];
}

int main(){
	std::ios::sync_with_stdio(false);
	cin>>n>>q; f=0;
	for (i=1;i<=maxn;i++) par[i]=i;
	for (i=1;i<=q;i++){
	  int a,b; string s;
	  cin>>a>>b; cin>>s;
	  if (a>b) swap(a,b); //*
	  if (c[a-1]==0) c[a-1]=(++cnt); if (c[b]==0) c[b]=(++cnt); //离散化  
	  int fa=find(c[a-1]); int fb=find(c[b]);
	  if (fa==fb){
	  	int t=v[c[a-1]]^v[c[b]]; //*
	  	if (((t==0&&s=="odd")||(t==1&&s=="even"))&&f==0) {
	  	  f=1; ans=i-1;
		}
	  }
	  else{
	  	int t=(s=="odd")?1:0;
	  	par[fa]=fb; v[fa]=t^v[c[a-1]]^v[c[b]]; //*
	  }
	}
	if (f==0) cout<<q<<endl; else cout<<ans<<endl; 
	return 0;
}

  

posted @ 2020-08-07 00:01  coastal_taipan  阅读(90)  评论(0编辑  收藏  举报