• Ural(Timus) 1003 Parity


    并查集

    题意:题意比较好懂简单说一下。一个序列,只有0,1;输入n,表示序列长度(从1到n标号),输入m,下面m个更新,每行都是a,b,string,表示说序列中下标a到下标b的元素中有偶数个或奇数个1.没得到一个更新就更新序列的信息,知道读入第k个信息,和已建立的信息矛盾,那么结束,输出k-1,表示前面k-1个更新不矛盾,如果m个更新都成立,那么输出m

    这题要转化一下,一转化就比较明显了。我们定义前缀和为sum[i]表示1到i的和,那么sum[b]-sum[a-1]=c[a]+c[a+1]+c[a+2]……c[b] , 即序列的[a,b]区间和

    因为序列中只有0,1所以区间和的奇偶性就是该区间拥有1的奇偶数,即[a,b]有偶数个1的话[a,b]区间和为偶数,同时也可知sum[b]和sum[a-1]同偶或同奇,即奇偶性相同

    如果[a,b]中有奇数个1,那么sum[b]和sum[a-1]奇偶性不同

    所以这个转化关系就出来了:[a,b]有偶数个1,那么sum[a-1]和sum[b]的奇偶性相同 ; [a,b]有奇数个1,那么sum[a-1]和sum[b]的奇偶性不同

    而无论如何都好,sum[i]的奇偶性只能是两种,或奇或偶,所以其实sum[0],sum[1],sum[2],……sum[n]其实分成了两个阵营,也就是两个集合

    如果读入了[a,b]为偶数,sum[a-1]和sum[b],应该在同一个集合中。如果它们互相在对方的敌对集合中,那么矛盾,跳出,否则的话,记得合并它们为1个集合,并且他们的敌对集合也要合并为1个集合

    如果读入[a,b]为奇数,sum[a-1]和sum[b],应该不在同一个集合中并且应该在对方的敌对集合中。如果它们在同一个集合中,那么矛盾,跳出,否则的话,sum[a-1]合并到sum[b]的敌对集合中,sum[b]合并到sum[i-1]的敌对集合中

    所以这题其实和经典在“朋友敌人”题目是相同(ab是朋友bc是朋友则ac是朋友,两人又共同敌人则是朋友,其实所有人分成了两个阵营)

    所以这种题目都要想方法怎么建立敌人集合

    一个比较好的方法是设置“虚拟”的敌人,已知有n个人,那么虚拟设置另外n个人(从n+1到2*n)标号,i+n表示i的敌人,其实i+n并不存在(只有n个人),它只是用了作为一个标志,标杆。这个方法有个好处,就是最初的时候我们什么信息都不知道,并不知道每个元素的敌人和朋友是谁,换言之我们不知道敌人集合是哪个(朋友集合可以初始化为它自己,即一开始自身就是个集合),所以我们用i+n作为i的敌人集合,然后在以后的更新中不断更新即可

    这不是唯一的方法但我认为是一个不容易出错,代码少,好理解的方法

    最后差点忘记了,这题数据太大了,10^9,而更新的次数只有5000,也就是说最坏情况下降产生10000个点,所以我们要离散化,而且可以发现序列的长度n,其实根本就没有用到,不需要它

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 10010 //最多10000个点
    #define M 5010
    #define min(a,b) a<b?a:b
    #define max(a,b) a>b?a:b
    
    int m,np;
    struct ran{
        int l,r,v;
    }a[M];
    struct point{
        int n,m;
    }c[N];
    int p[2*N];
    
    int cmp(struct point a ,struct point b)
    {
        return a.n<b.n;
    }
    
    int init() //输入数据和离散化
    {
        scanf("%d",&m);
        np=0;
        for(int i=0; i<m; i++)
        {
            int l,r;
            char s[5];
            scanf("%d%d%s",&l,&r,s);
            a[i].v=(s[0]=='o');
            c[np].m=i;   c[np].n=l;
            c[np+1].m=i; c[np+1].n=r;
            np+=2;
        }
        sort(c,c+np,cmp);
        int mm,nn=0;
        for(int i=0; i<np; i++)
        {
            if(i==0 || c[i].n != c[i-1].n) ++nn;
            mm=c[i].m; a[mm].r=a[mm].l; a[mm].l=nn;
        }
    //    for(int i=0; i<m; i++) printf("[%d,%d] %d\n",a[i].l,a[i].r,a[i].v);
        //离散化结束
        return nn;
    }
    
    int find(int x)
    {
        return x==p[x] ? x : p[x]=find(p[x]);
    }
    
    
    void solve(int n)
    {
        for(int i=0; i<=2*N+1; i++) p[i]=i;
        int res=m;
        for(int i=0; i<m; i++)
        {
            int l=a[i].l , r=a[i].r , v=a[i].v;
            int t=max(l,r) , tt=min(l,r);
            l=tt-1; r=t;
    
            int fal,far,eml,emr;
            fal=find(l);
            far=find(r);
            eml=find(l+n+1);
            emr=find(r+n+1);
    
            if(!v)
            {
                if(fal == emr && far == eml)
                { res=i; break;}
                p[fal]=far;
                p[eml]=emr;
            }
            else
            {
                if(fal == far)
                { res=i; break; }
                p[fal]=emr;
                p[far]=eml;
            }
        }
        printf("%d\n",res);
    }
    
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF && n!=-1)
        {
            n=init();
            solve(n);
        }
        return 0;
    }
  • 相关阅读:
    文本替换
    国际时间转化为北京时间
    nginx 白名单
    System.Web.HttpException 超过了最大请求长度。
    nginx 优化
    nginx 502 504
    nginx 配置文件相关参数
    nginx location指令 正则表达式
    子网下连接路由器配置
    Java初学者
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2998722.html
Copyright © 2020-2023  润新知