这个博客是写给自己看的,加深一下对题目的理解,不太具有参考价值
这道题选择用map来缩小存储的范围,也可以用HASH;
题目思路和HDU3038很相似
以靠后的数字作为根节点来构建一个并查集,节点之间的关系有两种
1.a b even : v[a - 1] = 0;表示a到b之间有偶数个1;
2.a b odd : v[a - 1] = 1;表示a到b之间有奇数个1;
由于a和b可能很大,所以对于每个a, b都用insert()处理一次
int _insert(int a)
{
if(mp.find(a) == mp.end()) mp[a] = total++; //查看当前数字是否已经被编号过从0开始编号
return mp[a];
}
如果输入的a b不在同一集合里就进行合并
pre[ta] = tb;
rela[ta] = (rela[b] + temp + 2 - rela[a])%2;
ta tb代表a b的根节点
下面的算式和3038这题很相似,这里一定记得要加 2,不然会出现负值,在这里错了好久。
用来记录父节点的数组pre要初始化为-1,不然会死循环,因为a-1的原因 会用到pre[0];
以下是自己写的代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <map>
using namespace std;
map<int, int> mp;
int rela[10010];
int pre[10010];
int total;
int _insert(int a)
{
if(mp.find(a) == mp.end()) mp[a] = total++; //查看当前数字是否已经被编号过从0开始编号
return mp[a];
}
int Find(int a)
{
if(pre[a] == -1)return a;
int temp = Find(pre[a]);
rela[a] = (rela[a] + rela[pre[a]])%2;
return pre[a] = temp;
}
int main()
{
int len;
int q;
while(cin >> len)
{
memset(rela, 0, sizeof(rela));
memset(pre, -1, sizeof(pre));
mp.clear();
total = 0;
cin >> q; //问题个数
int ans = q;
for(int i = 0; i < q; ++i)
{
//cout << Find(1)<<endl;
int a, b;
char s[6];
scanf("%d%d%s", &a, &b, &s); //读进三个数
if(ans != q)
continue;
int temp; //记录当前奇偶
--a; //计算需要用到闭区间
if(s[0] == 'e')temp = 0;
else temp = 1;
a = _insert(a); //对没有遇到过的数进行编号
b = _insert(b);
int ta = Find(a); //查找某个编号的根节点
int tb = Find(b);
if(ta == tb) //判断是否是同组
{
if((rela[a] + rela[b])%2 != temp)
{
ans = i;
/*if(total == 101)
cout << rela[a]<<' '<< rela[b]<<endl;
system("pause");*/
continue;
}
}
else
{
pre[ta] = tb;
rela[ta] = (rela[b] + temp + 2 - rela[a])%2;
}
}
cout << ans<<endl;
}
return 0;
}