zoukankan      html  css  js  c++  java
  • 1290C. Prefix Enlightenment(带权并查集)

    一行上有n盏灯,编号从1到n。每个人的初始状态均为关闭(0)或打开(1)。

    您得到了{1,2,…,n}的k个子集A1,…,Ak,因此任何三个子集的交集都是空的。换句话说,对于所有1≤i1<i2 <i3≤k,Ai1∩Ai2∩Ai3=∅。

    在一项操作中,您可以选择这k个子集之一,并切换其中的所有灯的状态。对于给定的子集,可以确保使用这种类型的操作使所有的灯同时亮起。

    令mi为使第i个指示灯同时点亮所需的最少操作次数。请注意,其他灯(在i + 1和n之间)的状态没有任何条件,它们可以熄灭或点亮。

    您必须为所有1≤i≤n计算mi。

    题解:

    带权并查集的高级应用,说实话有点一知半解,很多2400分的题把基本知识点考察的很透彻。

    //问题可以转化为
    //每个集合拆成两个点,取点和不取点 
    //然后每个集合内的点,如果本来就是亮的,和不取点连边, 
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=6e5+100;
    const int inf=1e9;
    int n,k,a[maxn];
    vector<int> g[maxn];
    string s;
    int father[maxn],w[maxn],ans;
    int findfather (int x) {
        int a=x;
        while (x!=father[x]) x=father[x];
        while (a!=father[a]) {
            int z=a;
            a=father[a];
            father[z]=x;
        }
        return x;
    }
    void Union (int x,int y) {
        x=findfather(x);
        y=findfather(y);
        if (x!=y) {
            father[x]=y;
            w[y]+=w[x]; 
        }
    }
    int dsu (int x) {
        return min(w[findfather(x)],w[findfather(x+k)]);//这个集合取或不取的最小值 
    }
    int main () {
        scanf("%d%d",&n,&k);
        cin>>s;
        for (int i=1;i<=k;i++) {
            int x;
            scanf("%d",&x);
            for (int j=0;j<x;j++) {
                int y;
                scanf("%d",&y);
                g[y].push_back(i);
            }
        }
        for (int i=1;i<=k*2;i++) father[i]=i,w[i]=(i>k);//不取为0,取为1 
        w[0]=inf;
        for (int i=1;i<=n;i++) {
            if (g[i].size()==1) {
                //如果这个点只在一个集合
                //x表示要使这个灯不亮的集合状态 
                int x=g[i][0]+(s[i-1]=='1')*k;
                ans-=dsu(g[i][0]);//答案减去这个集合取或不取的较小值 
                Union(x,0);//x和无限大的点连接,强制不取 
                ans+=dsu(g[i][0]);//答案加上这个集合取或不取的较小值 
            }
            else if (g[i].size()==2){
                int x=g[i][0];
                int y=g[i][1];
                if (s[i-1]=='0') {
                    if (findfather(x)!=findfather(y+k)) {
                        ans-=dsu(x)+dsu(y);
                        Union(x,y+k);
                        Union(x+k,y);
                        ans+=dsu(x);
                    }
                }
                else {
                    if (findfather(x)!=findfather(y)) {
                        ans-=dsu(x)+dsu(y);
                        Union(x,y);
                        Union(x+k,y+k);
                        ans+=dsu(x);
                    }
                }
            }
            printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    zookeeper使用场景
    zookeeper安装配置
    hadoop 远程调试
    deep learning笔记
    Sentiment Analysis(1)-Dependency Tree-based Sentiment Classification using CRFs with Hidden Variables
    PRML阅读笔记 introduction
    Python 学习笔记(2)
    python nltk 学习笔记(5) Learning to Classify Text
    python nltk 学习笔记(4) Writing Structured Programs
    python nltk 学习笔记(3) processing raw text
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14353277.html
Copyright © 2011-2022 走看看