题目链接:
POJ 1733 Party Game
题意:
有n个数字,每个数字非0即1,有m条语句,每条语句:l,r,even/odd,表示l到r区间上有奇/偶个1.
问最多前多少条语句是正确的?
分析:
和POJ 3038 How many answers are wrong? http://acm.hdu.edu.cn/showproblem.php?pid=3038 类似。
用val[i]表示从i到根节点路径上含有1的数量的奇偶性。在寻找根节点的同时更新路径上的val。
比较麻烦的是数据范围。n<=1000000000,而m<=5000.
①:可以用map来标记各个读入点的次序,相当于有个代号,在map里没读入的话就添加进map
在find()和mix()函数里相当于是对代号的操作,代号具有唯一性。
由于m<=5000,所以最多会读入10000个相异的数,那么对于pre数组和val数组都是可以接受的了。
②:hash思路。同样是代号的想法,把l(或r) mod maxn 值相同的归在一类,
用head数组的下标记录这类,head的数值表示最后一类的读入位置。和最短路里链式前向星的查找类似。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int maxn=10010;
int pre[maxn],val[maxn],n,m,l,r,w;
char s[10];
int find(int x)
{
if(pre[x]==x) return x;
int tmp=find(pre[x]);
val[x]=(val[x]+val[pre[x]])%2;
return pre[x]=tmp;
}
int mix(int x,int y,int z)//语句正确,mix返回1,否则返回0。
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
pre[fx]=fy;
val[fx]=(val[y]-val[x]+z)%2;
return 1;
}
else
{
if(abs(val[x]-val[y])%2==z) return 1;
return 0;
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
while(~scanf("%d",&n)&&n)
{
for(int i=0;i<maxn;i++)
{
pre[i]=i;
val[i]=0;
}
scanf("%d",&m);
int ok=0;
int ans=0;
int index=0;
map<int,int> mp;
for(int i=1;i<=m;i++)
{
scanf("%d%d%s",&l,&r,s);
if(s[0]=='e') w=0;
else w=1;
l--;//这样做就可以合并相邻的区间,例如:读入l=1,r=2和l=3,r=4
if(mp.find(l)==mp.end()) mp[l]=index++;
//find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器
if(mp.find(r)==mp.end()) mp[r]=index++;
//假设前x条语句是正确的,第x+1条是错的。那么前x次读入ok都为0,第x+1次读入由于ok=0,mix()返回0
//所以执行else语句,ok变为1,ans=i-1=(x+1)-1=x.从x+2开始由于ok=1,不会执行||后面的判断,恒continue.
if(ok||mix(mp[l],mp[r],w)) continue;
else ok=1;
if(ok) ans=i-1;
}
if(ok==0) ans=m;//所有的语句都是正确的
printf("%d\n",ans);
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
const int maxn=5050;
int n,m,l,r,w,tot;
int head[maxn],val[maxn],pre[maxn];
char s[10];
struct Point{
int value,next;
}point[maxn];
int hash(int n)
{
int m=n%maxn;
for(int i=head[m];i!=-1;i=point[i].next)
if(point[i].value==n) return i;
point[tot].value=n;
point[tot].next=head[m];
head[m]=tot++;
return (tot-1);
}
int find(int x)
{
if(pre[x]==x) return x;
int tmp=find(pre[x]);
val[x]=(val[x]+val[pre[x]])%2;
return pre[x]=tmp;
}
int mix(int x,int y,int z)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
pre[fx]=fy;
val[fx]=(val[y]-val[x]+z)%2;
return 1;
}
else
{
if(abs(val[x]-val[y])%2==z) return 1;
return 0;
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
while(~scanf("%d",&n)&&n)
{
memset(head,-1,sizeof(head));
memset(val,0,sizeof(val));
for(int i=0;i<maxn;i++)
pre[i]=i;
tot=0;
scanf("%d",&m);
int ans=m;
int ok=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d%s",&l,&r,s);
l=hash(l-1);
r=hash(r);
if(s[0]=='e') w=0;
else w=1;
if(ok||mix(l,r,w)) continue;
else ok=1;
if(ok) ans=i-1;
}
printf("%d\n",ans);
}
return 0;
}