1. 程式人生 > 實用技巧 >《演算法競賽進階指南》0x41並查集 奇偶遊戲

《演算法競賽進階指南》0x41並查集 奇偶遊戲

題目連結:https://www.acwing.com/problem/content/241/

給出長度n,和m條記錄,每條記錄中說明一個區間中1的數量,其中序列是01序列,問到哪一個是最後一個正確的。

可以通過並查集解決,用字首異或和作為一段區間中1的個數的象徵。可以通過“邊帶權”的方式計算也可以通過擴充套件域的方式進行求解。

第一種求解方案:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 10010;
int
f[maxn*2],d[maxn*2],a[maxn*2]; struct node{ int l,r; int ans; }query[maxn]; int n,m; int num; int find(int x){ if(x==f[x])return x; int root=find(f[x]); d[x]^=d[f[x]]; return f[x]=root;//記住一定要用f[x]=root,否則f[x]沒得到更新 } int get(int x){ return lower_bound(a+1,a+num+1,x)-a; }
int main(){ cin>>n>>m; char s[10]; for(int i=1;i<=m;i++){ scanf("%d%d%s",&query[i].l,&query[i].r,s); if(s[0]=='e')query[i].ans=0; else query[i].ans=1; a[2*i-1]=query[i].l-1; a[2*i]=query[i].r; } sort(a+1,a+2*m+1); num
=unique(a+1,a+2*m+1)-(a+1); for(int i=1;i<=num;i++)f[i]=i; for(int i=1;i<=m;i++){ int x=get(query[i].l-1); int y=get(query[i].r); int ans=query[i].ans; int fx=find(x),fy=find(y); if(fx==fy){ if(d[x]^d[y]==ans)continue; else{ cout<<i-1<<endl; return 0; } }else{ f[fx]=f[y]; d[fx]=ans^d[x]^d[y]; } } cout<<m<<endl; return 0; }

第二種求解方案:構建擴充套件域,將一個點可能歸屬的集合拆成兩個推導集。

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = 10010;
int f[maxn*2];
int a[maxn*2];
int n,m,num;
struct node{
    int l,r,ans;
}query[maxn];
int find(int x){
    return (x==f[x]?x:f[x]=find(f[x]));
}
void Union(int x,int y){
    int fx=find(x);
    int fy=find(y);
    if(fx==fy)return ;
    f[fx]=fy;
    return ;
}
int get(int x){
    return lower_bound(a+1,a+num+1,x)-a;
}
int main(){
    cin>>n>>m;
    char s[10];
    for(int i=1;i<=m;i++){
        scanf("%d%d%s",&query[i].l,&query[i].r,s);
        query[i].ans=(s[0]=='o'?1:0);
        a[2*i-1]=query[i].l-1;
        a[2*i]=query[i].r;
    }
    sort(a+1,a+2*m+1);
    num=unique(a+1,a+2*m+1)-(a+1);
    for(int i=1;i<maxn-1;i++)f[i]=i;
    for(int i=1;i<=m;i++){
        int x_odd=get(query[i].l-1);
        int y_odd=get(query[i].r);
        int x_even=x_odd+num;
        int y_even=y_odd+num;
        int ans=query[i].ans;
        if(ans){
            if(find(x_odd)==find(y_odd))
            {
                cout<<i-1<<endl;
                return 0;
            }
            Union(x_odd,y_even);
            Union(y_odd,x_even);
        }else{
            if(find(x_odd)==find(y_even))
            {
                cout<<i-1<<endl;
                return 0;
            }
            Union(x_odd,y_odd);
            Union(y_even,x_even);
        }
    }
    cout<<m<<endl;
    return 0;
}