vijos 1112 小胖的奇偶 并查集+哈希表

描述 Description  
  huyichen和xuzhenyi在玩一个游戏:他写一个由0和1组成的序列。
huyichen选其中的一段(比如第3位到第5位),问他这段里面有奇数个1
还是偶数个1。xuzhenyi回答你的问题,然后huyichen继续问。
xuzhenyi有可能在撒谎。huyichen要检查xuzhenyi的答案,指出在xuzhenyi的第几个回答一定有问题。
有问题的意思就是存在一个01序列满足这个回答前的所有回答,而且不存在序列
满足这个回答前的所有回答及这个回答。
     
     
  输入格式 Input Format  
  第1行一个整数,是这个01序列的长度(<=1000000000)
第2行一个整数,是问题和答案的个数。
第3行开始是问题和答案,
每行先有两个整数,表示你询问的段的开始位置和结束位置。
然后是xuzhenyi的回答。odd表示有奇数个1,even表示有偶数个1。
     
     
  输出格式 Output Format  
  输出一行,一个数X,表示存在一个01序列满足第1到第X个回答,
但是不存在序列满足第1到第X+1个回答。如果所有回答都没问题,你就输出
所有回答的个数。
     
     
   
     
     
  样例输入 Sample Input  
  10 5 1 2 even 3 4 odd 5 6 even 1 6 even 7 10 odd
     
     
  样例输出 Sample Output  
  3
     
     
  来源 Source  
  huyichen
     
     
 
Flag
  Accepted
题号
  P1112
类型(?)
  并查集
通过
  592人
提交
  2720次
通过率
  22%
难度
  3
 
     
     
 
提交 讨论 题解 状态
 
     
     
   
     

 
 

 

 

 

 

首先询问的个数m<=5000
如何转化成并查集?
a b even等价于(0..a-1)与(0..b)同奇同偶
a b odd等价于(0..a-1)与(0..b)不同奇同偶
这样对于a b even,就union(same(a-1),same(b))&union(diff(a-1),diff(b))
对于a b odd,则union(same(a-1),diff(b))&union(diff(a-1),same(b))
same(x)和diff(x)随便选,比如same(x):=x;diff(x):=x+block;
反之,find(same(a-1))=find(same(b))等价于a b even(此时必然有find(diff(a-1))=find(diff(b))),find(diff(a-1))=find(same(b))等价于a b odd(同样此时必然有find(same(a-1))=find(diff(b)))这样就可以判断了.
循环每个提问,先判断,不符合就writeln&break,否则union;
但这样还不可以,因为n<=10^9,会MLE.
这就用着hash了.n很大,但m很小(<=5000),这样会出现的数<=10000个,所以只需要对这10000个数DisUnionJet,为了把这10000个数一一映射到0..10000中,我们用hash.function hash(x)是原来的x在hashtable中的位置,原来的x则映射在hashtable中.以后就可以用hash(x)代替x了.这里的hash方法叫做开放寻址法(参见算法导论)
当然,这样same(x):=same(hash(x));diff(x):=diff(hash(x))
另外再设一个bb:boolean来判断如果循环后i=n时有没有经历break;
这样,程序'应该'就完成了
程序有3个难点:(1)区间奇偶转化为两区间奇偶是否相同(还是比较简单的)(2)两区间奇偶是否相同转化成并查集模型(3)利用hash压缩空间. 

 

 

 

 

#include
#include
#include
using namespace std;
const int BLOCK=10000;
const int HASHING=6000;//important  
int fath[2*BLOCK+1],hash_table[HASHING+1];
int hash(int x)//构建哈希表
{
    int ret;
    ret=x%HASHING;
    while(hash_table[ret]!=-1&&hash_table[ret]!=x) ret=(ret+1)%HASHING;
    hash_table[ret]=x;
    return ret;
}//important
int find(int x){return fath[x]==x?x:fath[x]=find(fath[x]);}
void uion(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y) return ;
    fath[x]=y;
}
int main()
{
    int len,n;
    while(cin>>len>>n)
    {
        int ans,flag=0;
        for(int i=1;i<2*BLOCK+1;i++) fath[i]=i;
        memset(hash_table,-1,sizeof(hash_table));//初始化哈希表  important
        for(int ci=1;ci<=n;ci++)
        {
            int a,b,signal;
            string str;
            cin>>a>>b>>str;
            if(flag) continue;
            signal=(str=="even"?1:0);//1表示偶数,0表示奇数
            a=hash(a-1);//important
            b=hash(b);//important
            if(signal)
            {
                if(find(a)==find(b+BLOCK)) {ans=ci-1;flag=1;continue;}
                uion(a,b);
                uion(a+BLOCK,b+BLOCK);
            }
            else
            {
                if(find(a)==find(b)) {ans=ci-1;flag=1;continue; }
                uion(a,b+BLOCK);
                uion(a+BLOCK,b);
            }
        }
        if(flag==0) ans=n;
        cout<    }
    return 0;
}               
               

 

你可能感兴趣的:(acm_并查集)