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; }