02年的论文题,各种优化最后搞个种类并查集。
说实话原论文里的实现并不是很会。。。。不知道那个并查集要怎么搞。
于是琢磨了一小下终于弄通了种类并查集是怎么回事了。
这题由于存在一个same合并,即合并为同一类,所以要在原有的merge上做个判断,不妨将集合看成无根树,于是当u和v合并时若两者不同类,则dis(x,y)=dis(x,u)+dis(v,y)+1,若两者同类,则将节点u和节点v重合,于是有dis(x,y)=dis(x,u)+dis(v,y),这样就好了。
哈希表随便写的。。。。跑了300多MS
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int p=2000000+3;
int pa[10005],cnt,dis[10005];
vector<pair<int,int> >hash[p];
int findset(int x){
if(pa[x]==x)return x;
int tmp=findset(pa[x]);
dis[x]=(dis[x]+dis[pa[x]])&1;
return pa[x]=tmp;
}
void merge(int u,int v,bool flag){
int x=findset(u),y=findset(v);
if(x!=y){
pa[x]=y;
if(flag)dis[x]=(dis[u]+dis[v])&1;
else dis[x]=(dis[u]+dis[v]+1)&1;
}
}
void insert(int x){
int t=x%p;
for(int i=0;i<hash[t].size();i++)
if(hash[t][i].first==x)return;
hash[t].push_back(make_pair(x,++cnt));
pa[cnt]=cnt;dis[cnt]=0;
}
int find(int x){
int t=x%p;
for(int i=0;i<hash[t].size();i++)
if(hash[t][i].first==x)return hash[t][i].second;
}
char s[10];
int main(){
//freopen("a.in","r",stdin);
int n,l,r;scanf("%d%d",&n,&n);
int i;
for(i=0;i<n;i++){
scanf("%d%d%s",&l,&r,s);
l--;
insert(l);l=find(l);
insert(r);r=find(r);
if(s[0]=='e'){
if(findset(l)!=findset(r))merge(l,r,true);
else if(dis[l]!=dis[r])break;
}else{
if(findset(l)!=findset(r))merge(l,r,false);
else if(dis[l]==dis[r])break;
}
}
printf("%d",i);
return 0;
}