题目
题解思路
题目意思要开1e9的数组,但是这样会超限。要对输入的数据进行离散化处理。利用map构建一个hash映射。因为原来的序列的长度编号并没有对序列产生影响,例如 下图中1 10 1中 插入个 3 10 1 并此时3的编号为4,并没有让题目的数据关系产生改变!
然后就是带权并查集了,根据之前的区间处理小技巧,要让左区间先自减,让两边闭合的区间变成左开右闭。
然后就是维护这个树了,在两个点都在树里就能判断,没有就合并入树。因为题目只存在奇数或者偶数的情况,所以进行模运算,0代表偶数,1代表奇数。在压缩路径和合并时中进行取模即可。
坑点
- 全部正确是输出总数,一开始没注意到Wa了好久。
- 取模时最后全部先加上取模值防止出现负数,Wa了好久
AC代码
#include <iostream>
#include <string>
#include <cstdio>
#include <map>
using namespace std;
map <long long ,int > li;
int a[50005];
int w[50005];
int find2(int x )
{
if ( x != a[x] )
{
int t = a[x];
a[x] = find2(a[x]);
w[x] = (w[x] + w[t])%2;
}
return a[x];
}
int main()
{
int k,flag = 0;
long long n;
string j1 = "even";
string t = "";
// freopen("xxxx.txt","r",stdin);
scanf("%lld%d",&n,&k);
for (int i = 0 ;i <= 10005 ; i++ )
a[i] = i ;
int pit = 0 ;
for (int i = 1 ;i <= k ; i++ )
{
long long b,c,d;
scanf("%lld%lld",&b,&c);
cin>>t;
if (flag != 0)
continue;
if ( b > c)
swap(b,c);
b--;
if ( li.count(b) == 0 )
{
pit++;
li[b] = pit;
}
if ( li.count(c) == 0 )
{
pit++;
li[c] = pit;
}
b = li[b];
c = li[c];
if( t == j1 )
d = 0;
else
d = 1;
int fx = find2(b);
int fy = find2(c);
if ( fx == fy )
{
if ( d != ( w[b] - w[c] + 2)%2 )
flag = i-1;
}else
{
a[fx] = fy;
w[fx] = ( -w[b] + d + w[c] + 2)%2;
}
if ( i == k && flag == 0)
flag = k;
}
printf("%d\n",flag);
return 0;
}