C. Prefix Enlightenment(并查集)

http://codeforces.com/problemset/problem/1290/C

题意:

给出一个n长01串,m个位置集合,如果选中某个集合,会将集合中的所有位置进行翻转。

问,对于 i [ 1 , n ] i\in[1,n] ,求将前i位变为1的最少集合数量。保证可行。保证每个位置只出现在最多两个集合。

代码:

一位原来是0,那么说明需要1个集合。如果有两个集合只能选其一。也就是说 A ¬ B A\wedge \neg B 或者 ¬ A B \neg A\wedge B 。原来是1就是 A B A\wedge B 或者 ¬ A ¬ B \neg A\wedge \neg B

那么就是拆点成 A A ¬ A \neg A A A 点权1, ¬ A \neg A 点权0。

然后每到一个位置,将需要连的点连起来。花费计算为:删除合并前的集合(带权并查集)的权值,加入合并后的权值。

一个点必选只需要,不选的那个点的集合里面塞一个值很大的点即可。

代码:

/*
 *  Author : Jk_Chen
 *    Date : 2020-03-22-10.13.14
 */
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=3e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
    while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/

char x[maxn];
int pos[maxn][2];

int n,m;
int fa[maxn*2];
int val[maxn*2];
int Not(int x){return x+m; }
int fin(int x){return fa[x]==x?x:fa[x]=fin(fa[x]); }
void un(int x,int y){
    int f1=fin(x),f2=fin(y);
    if(f1==f2)return;
    fa[f1]=f2;
    val[f2]+=val[f1];
}
int getMin(int x){
    return min(val[fin(x)],val[fin(Not(x))]);
}

int main(){
    n=rd,m=rd;
    rep(i,1,m)val[i]=1,fa[i]=i,fa[Not(i)]=Not(i);
    fa[0]=0;val[0]=inf;

    scanf("%s",x+1);
    rep(i,1,m){
        int _=rd;
        while(_--){
            int bit=rd;
            if(pos[bit][0])pos[bit][1]=i;
            else pos[bit][0]=i;
        }
    }

    int ans=0;
    rep(i,1,n){
        if(x[i]=='0'){
            if(pos[i][1]){
                if(fin(pos[i][0])!=fin(Not(pos[i][1]))){
                    ans-=getMin(pos[i][0])+getMin(pos[i][1]);
                    un(pos[i][0],Not(pos[i][1]));
                    un(pos[i][1],Not(pos[i][0]));
                    ans+=getMin(pos[i][0]);
                }
            }
            else{
                ans-=getMin(pos[i][0]);
                un(0,Not(pos[i][0]));
                ans+=getMin(pos[i][0]);
            }
        }
        else{
            if(pos[i][1]){
                if(fin(pos[i][0])!=fin(pos[i][1])){
                    ans-=getMin(pos[i][0])+getMin(pos[i][1]);
                    un(pos[i][0],pos[i][1]);
                    un(Not(pos[i][1]),Not(pos[i][0]));
                    ans+=getMin(pos[i][0]);
                }
            }
            else{
                ans-=getMin(pos[i][0]);
                un(0,pos[i][0]);
                ans+=getMin(pos[i][0]);
            }
        }
        printf("%d\n",ans);
    }

    return 0;
}

/*_________________________________________________________end*/

发布了773 篇原创文章 · 获赞 345 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/105069732