这个题应该思路蛮多的,,,,,一个比较成熟的思路就是用并查集,,,其实不是很好想到我觉得(事实上很像线段树什么的好吧),,,,就是 1 2 odd就看成sum(2)-sum(0)为odd,放在一起,然后相减为even的放在一起,,,之后要是有矛盾的(二合一)就错了,,,,,,这题到这里其实就是一个模板题嘛。。。。。敲敲并查集路径压缩下就好,,,只是数据量大内存不够。。。。所以要用到HASH(现学现卖。。。)哎,,,,,,,就说这么多了,,,别的也没啥,,顺便复习一下并查集。。。。。。。
先讲一下hash:
把一个值映射到特定的key上,(通过一个固定的算法函数),一般是变成一个数,,,,知道了这个数,也就知道了在原来的位置;
并查集:
原理很好懂,代码还是模板,注意一下路径压缩就好,,主要就是两个点连线,一个新来的找到以前的人的大哥并与之连线,大家就是手拉手的亲兄弟了,两边拉一起了就错了矛盾了。。。。。。
贴代码写注释。。。。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int hash1[11111];
int pre[22222];
int m,n;
void chushihua() //并查集的初始化,,,之前每个人都只有自己这么一个兄弟。。。。。
{
for(int i=0;i<22222;i++) pre[i]=i;
}
int find(int x) //查找是哪个圈子的,,,,一直往上找,,,如果大哥不是它本身的话,,就去找他的大哥,,直到拜人家最大的大哥为大哥
{
int r=x;
while ( pre[r ] != r )
r=pre[r ];
int i=x , j ;
while( i != r ) //这个就是路径压缩了,,所有人都是一个人的小弟,,,没有小弟的小弟了
{
j = pre[ i ];
pre[ i ]= r ;
i=j;
}
return r ;
}
void join(int x,int y) //加入帮会,,,,,要是俩人的大哥不一样,,,就合并一下
{
int fx=find(x),fy=find(y);
if(fx!=fy)
pre[fx]=fy;
}
int hahahash(int x)
{
int key=x%11111;
while(hash1[key]!=-1&&hash1[key]!=x) key=(key+10)%11111; //如果取余11111的有数字了,,那就加10再取余,,,,省空间嘛。。。。
if(hash1[key]==-1) hash1[key]=x;
return key;
}
int main()
{
while(scanf("%d",&n)&&n!=-1)
{
chushihua();
scanf("%d",&m);
memset(hash1,-1,sizeof(hash1));
int a,b;
int ans=-1;
char s[10];
int i;
for(i=0;i<m;i++)
{
scanf("%d%d%s",&a,&b,s);
if(ans!=-1) continue; //已经不对了,,剩下的就读取一下就拉倒了也别管别的了
if(a>b) swap(a,b);
a=hahahash(a-1);
b=hahahash(b);
if(strcmp(s,"even")==0)
{
if(find(a)==find(b+11111)||find(a+11111)==find(b)) //发现两个帮派合一起了
ans=i;
join(a,b);
join(a+11111,b+11111); //加的11111(maxn)就是相当于开了两个数组,,,,一个是同奇偶一个是不同奇偶的,,,,,,
}
else
{
if(find(a)==find(b)||find(a+11111)==find(b+11111))
ans=i;
join(a+11111,b);
join(b+11111,a);
}
}
printf("%d\n",ans!=-1?ans:m);
}
return 0;
}