TimusOJ 1003. Parity 题解

题目传送门

题目大意: 给出若干个回答,表示某个区间内 1 1 的个数是奇数还是偶数,找到一个最大的 x x ,满足前 x x 个回答之间相互不矛盾。

题解

显然能进行这样一个转化:假如区间内 1 1 的个数是奇数,那么区间异或和就是 1 1 ,否则异或和就是 0 0

s u m i sum_i 表示前 i i 位的异或和,那么每次询问区间 [ l , r ] [l,r] ,相当于看 s u m l 1   x o r   s u m r sum_{l-1}~xor~sum_r 的值是否满足要求,假如满足要求就无事发生。

假如不满足要求的话,就再看一下 l 1 l-1 r r 这两个位置之间之前有没有联系,假如有,那么就找到答案了,假如没有联系,那么让 r r 以及与 r r 有关系的位置异或 1 1 即可使他们满足要求。

处理完每个回答后,要让 l 1 l-1 r r 产生联系,这个用并查集维护即可。因为 n n 的范围比较大,所以这个并查集是个map。

注:可以发现,两个有联系的位置之间,一个异或了 1 1 之后必须使另一个也异或 1 1 才能满足之前的要求。

代码如下:

#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
#define maxn 5010

int n,m;
map<int,int> sum,f;
int findfa(int x){return x==f[x]?x:f[x]=findfa(f[x]);}

int main()
{
	while(scanf("%d",&n),n!=-1)
	{
		scanf("%d",&m);
		sum.clear();f.clear();
		int x,y,xx,yy,z,ans=m;char s[5];
		for(int i=1;i<=m;i++)
		{
			scanf("%d %d %s",&x,&y,s);x--;
			if(ans!=m)continue;
			if(f.find(x)==f.end())sum[x]=0,f[x]=x;
			if(f.find(y)==f.end())sum[y]=0,f[y]=y;
			xx=findfa(x);yy=findfa(y);z=(s[0]=='o');
			if(xx!=yy)
			{
				if((sum[y]^sum[x])!=z)
				{
					for(map<int,int>::iterator i=sum.begin(),j=f.begin();i!=sum.end();i++,j++)
					if(findfa(j->second)==yy)i->second^=1;
				}
				f[xx]=yy;
			}
			else if((sum[y]^sum[x])!=z)ans=i-1;
		}
		printf("%d\n",ans);
	}
}
/*
附赠一组数据
10
10
8 10 odd
1 8 even
2 8 odd
1 10 odd
5 6 even
1 1 even
4 4 even
6 6 even
1 6 even
3 4 odd
-1

ans=5
*/
发布了234 篇原创文章 · 获赞 100 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/a_forever_dream/article/details/103365579