题解:CF1290C Prefix Enlightenment

· · 题解

被迫营业讲课于是选了 dsu,这是例题。

对于每个位置,考虑包含这个位置的所有集合,进行分讨:

然后这个东西光速发现可以用并查集维护,二倍域维护互斥点就好了。

多维护两个点作为必选和必不选即可,然后对于没有绑定在这两个点上的连通块,显然是互斥的两个连通块对二选一,直接维护一个 \min 的和即可。

前缀问题直接一边扫把边建出来的同时维护答案即可。

哪有紫啊。

#include<bits/stdc++.h>
using namespace std;
vector<int>ve[300005];
int fa[600005];
int siz[600005];
int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
int ans;
void merge(int x,int y){
    x=find(x),y=find(y);
    if(x==y)return;
    siz[y]+=siz[x];
    fa[x]=y;
}
int main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=k*2+1;i++)
    fa[i]=i;
    for(int i=1;i<=k;i++)
    siz[i]=1;
    string s;
    cin>>s;
    for(int i=1;i<=k;i++){
        int m;
        cin>>m;
        while(m--){
            int x;
            cin>>x;
            ve[x].push_back(i);
        }
    }
    s=" "+s;
    for(int i=1;i<=n;i++){
        if(ve[i].size()==1){
            if(s[i]=='0'){
                if(find(0)!=find(ve[i][0]))
                ans-=min(siz[find(ve[i][0])],siz[find(k+ve[i][0])]);
                merge(0,ve[i][0]);
                merge(k*2+1,k+ve[i][0]);
            }else{
                if(find(0)!=find(ve[i][0]+k))
                ans-=min(siz[find(ve[i][0])],siz[find(k+ve[i][0])]);
                merge(0,ve[i][0]+k);
                merge(k*2+1,ve[i][0]);
            }
        }else if(ve[i].size()==2){
            if(s[i]=='0'){
                if(find(ve[i][0])==find(0)){
                    if(find(0)!=find(ve[i][1]+k))
                    ans-=min(siz[find(ve[i][1])],siz[find(k+ve[i][1])]);
                    merge(0,ve[i][1]+k);
                    merge(k*2+1,ve[i][1]);
                    goto nxt;
                }
                if(find(ve[i][1])==find(0)){
                    if(find(0)!=find(ve[i][0]+k))
                    ans-=min(siz[find(ve[i][0])],siz[find(k+ve[i][0])]);
                    merge(0,ve[i][0]+k);
                    merge(k*2+1,ve[i][0]);
                    goto nxt;
                }
                if(find(ve[i][0])==find(2*k+1)){
                    if(find(0)!=find(ve[i][1]))
                    ans-=min(siz[find(ve[i][1])],siz[find(k+ve[i][1])]);
                    merge(0,ve[i][1]);
                    merge(k*2+1,k+ve[i][1]);
                    goto nxt;
                }
                if(find(ve[i][1])==find(2*k+1)){
                    if(find(0)!=find(ve[i][0]))
                    ans-=min(siz[find(ve[i][0])],siz[find(k+ve[i][0])]);
                    merge(0,ve[i][0]);
                    merge(k*2+1,k+ve[i][0]);
                    goto nxt;
                }
                if(find(ve[i][0])!=find(ve[i][1]+k)){
                    ans-=min(siz[find(ve[i][0])],siz[find(k+ve[i][0])]),
                    ans-=min(siz[find(ve[i][1])],siz[find(k+ve[i][1])]);
                    merge(ve[i][0],ve[i][1]+k);
                    merge(ve[i][0]+k,ve[i][1]);
                    ans+=min(siz[find(ve[i][1])],siz[find(k+ve[i][1])]);
                }
            }else{
                if(find(ve[i][0])==find(2*k+1)){
                    if(find(0)!=find(ve[i][1]+k))
                    ans-=min(siz[find(ve[i][1])],siz[find(k+ve[i][1])]);
                    merge(0,ve[i][1]+k);
                    merge(k*2+1,ve[i][1]);
                    goto nxt;
                }
                if(find(ve[i][1])==find(2*k+1)){
                    if(find(0)!=find(ve[i][0]+k))
                    ans-=min(siz[find(ve[i][0])],siz[find(k+ve[i][0])]);
                    merge(0,ve[i][0]+k);
                    merge(k*2+1,ve[i][0]);
                    goto nxt;
                }
                if(find(ve[i][0])==find(0)){
                    if(find(0)!=find(ve[i][1]))
                    ans-=min(siz[find(ve[i][1])],siz[find(k+ve[i][1])]);
                    merge(0,ve[i][1]);
                    merge(k*2+1,k+ve[i][1]);
                    goto nxt;
                }
                if(find(ve[i][1])==find(0)){
                    if(find(0)!=find(ve[i][0]))
                    ans-=min(siz[find(ve[i][0])],siz[find(k+ve[i][0])]);
                    merge(0,ve[i][0]);
                    merge(k*2+1,k+ve[i][0]);
                    goto nxt;
                }
                if(find(ve[i][0])!=find(ve[i][1])){
                    ans-=min(siz[find(ve[i][0])],siz[find(k+ve[i][0])]),
                    ans-=min(siz[find(ve[i][1])],siz[find(k+ve[i][1])]);
                    merge(ve[i][0],ve[i][1]);
                    merge(ve[i][0]+k,ve[i][1]+k);
                    ans+=min(siz[find(ve[i][1])],siz[find(k+ve[i][1])]);
                }
            }
        }
        nxt:
        cout<<ans+siz[find(0)]<<'\n';
    }
    return 0;
}
// 就算如此,也一定是……

// 有个为这样的她著想的人;有个为这样的她感到生气的人;有个为这样的她而拋下一切,持续奔波的人。

// 根据那个人所说,「我会让你幸福」这句话,是擅自断定对方还没获得幸福。
// 这是猎艳专家、诈欺师和政治家经常使用的话术,让他人依赖自己的一种思想诱导。
// 因此,那个人没有说这种只是用来取悦对方的话语,仅以行动来展现。
// 尽管经常是白忙一场,尽管他的做法也很笨拙。

// 不过,光是这样,她便非常开心。

// 令人实在伤脑筋的是,能够感到开心这一点,没错,就已经是幸福了──