返回顶部

AcWing 239.奇偶游戏 (带权并查集/种类并查集)

  • 题意:你和朋友玩游戏,有个一\(01\)序列,你每次给出一个区间,朋友会回答这个区间中的\(1\)的个数是奇数还是偶数,但是你亲爱的朋友可能在撒谎,问在哪个询问你能确定你的朋友在撒谎,输出回合数.

  • 题解:假如区间\([l,r]\)所含的奇数个数为偶数的话,那么其前缀和\(s_{l-1}\)\(s_r\)所含的\(1\)的个数一定同奇同偶,如果\([l,r]\)所含奇数个数为奇数,\(s_{l-1}\)\(s_r\)奇偶性一定不同.

    所以我们对前缀和\(s\)进行维护,如果\([l,r]\)为偶数,那么我们可以将区间\(s_{l-1}\)\(s_r\)合并,并且它们之间的权值应该为\(0\),若为奇数则权值为\(1\),传递关系可以用异或来操作,核心思想依然是带权并查集,但是这题还需要离散化.

    此处顺便附上种类并查集的做法

  • 代码:

    #include <iostream>
    #include <iomanip>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <map>
    #include <set>
    #include <unordered_set>
    #include <unordered_map>
    #define ll long long
    #define db double
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int lcm(int a,int b){return a/gcd(a,b)*b;}
    
    inline int read()
    {
        int X=0; bool flag=1; char ch=getchar();
        while(ch<'0'|ch>'9') {if(ch=='-') flag=0; ch=getchar();}
        while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
        if(flag) return X;
        return ~(X-1);
    }
    
    int n;
    int m;
    int a,b;
    string op;
    int p[N];
    int d[N];
    unordered_map<int,int> S;
    
    int get(int x){
    	if(S.count(x)==0) S[x]=++n;
    	return S[x];
    }
    
    int find(int x){
    	if(p[x]!=x){
    		int root=find(p[x]);
    		d[x]^=d[p[x]];
    		p[x]=root;
    	}
    	return p[x];
    }
    
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
       	
        rep(i,1,10010) p[i]=i;
    
        cin>>n>>m;
        n=0;
        int ans=m;
    
        rep(i,1,m){
        	cin>>a>>b>>op;
       		a=get(a-1),b=get(b);
        	int fa=find(a);
        	int fb=find(b);
    
        	int t=0;
        	if(op=="odd") t=1;
    
        	if(fa==fb){
        		if((d[a]^d[b])!=t){
        			ans=i-1;
        			break;
        		}
        	}
        	else{
        		p[fa]=fb;
        		d[fa]=d[a]^d[b]^t;
        	}
        }
    
        cout<<ans<<'\n';
    
        return 0;
    }
    
    **************************************************************
      
    #include <iostream>
    #include <iomanip>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <map>
    #include <set>
    #include <unordered_set>
    #include <unordered_map>
    #define ll long long
    #define db double
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int lcm(int a,int b){return a/gcd(a,b)*b;}
    
    inline int read()
    {
        int X=0; bool flag=1; char ch=getchar();
        while(ch<'0'|ch>'9') {if(ch=='-') flag=0; ch=getchar();}
        while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
        if(flag) return X;
        return ~(X-1);
    }
    
    int n,m;
    int p[N];
    int a,b;
    string op;
    unordered_map<int,int> S;
    
    int get(int x){
    	if(S.count(x)==0) S[x]=++n;
    	return S[x];
    }
    
    int find(int x){
    	if(p[x]!=x) p[x]=find(p[x]);
    	return p[x];
    }
    
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        cin>>n>>m;
        int cnt=10010/2;
        n=0;
        rep(i,1,10010) p[i]=i;
        int ans=m;
        rep(i,1,m){
        	cin>>a>>b>>op;   //p[x]存偶数,p[x+n]存奇数
        	a=get(a-1),b=get(b);
        	if(op=="even"){
        		if(find(a+cnt)==find(b)){
        			ans=i-1;
        			break;
        		}
        		p[find(a)]=find(b);
        		p[find(a+cnt)]=find(b+cnt);
        	}
        	else{
        		if(find(a)==find(b)){
        			ans=i-1;
        			break;
        		}
        		p[find(a)]=find(b+cnt);
        		p[find(a+cnt)]=find(b);
        	}
        }
    
        cout<<ans<<'\n';
    
        return 0;
    }
    
    
    
posted @ 2020-11-13 01:03  Rayotaku  阅读(103)  评论(0编辑  收藏  举报