zoukankan      html  css  js  c++  java
  • 小胖的奇偶(Viojs1112)题解

    原题:

    题目描述

       huyichen和xuzhenyi在玩一个游戏:他写一个由0和1组成的序列。 huyichen选其中的一段(比如第3位到第5位),问他这段里面有奇数个1 还是偶数个1。xuzhenyi回答你的问题,然后huyichen继续问。 xuzhenyi有可能在撒谎。huyichen要检查xuzhenyi的答案,指出在xuzhenyi的第几个回答一定有问题。 有问题的意思就是存在一个01序列满足这个回答前的所有回答,而且不存在序列 满足这个回答前的所有回答及这个回答。

    输入格式

    第1行一个整数,是这个01序列的长度1000000000)(≤1000000000) 第2行一个整数,是问题和答案的个数(5000)(≤5000)。 第3行开始是问题和答案, 每行先有两个整数,表示你询问的段的开始位置和结束位置。 然后是xuzhenyi的回答。odd表示有奇数个1,even表示有偶数个

    输出格式

    输出一行,一个数X,表示存在一个01序列满足第1到第X个回答, 但是不存在序列满足第1到第X+1个回答。如果所有回答都没问题,你就输出 所有回答的个数。


    很明显,这道题是并查集(不要问我怎么看出来的)。

    由于数据太大,需要离散化。

    所谓离散化,就是把较大的一组数进行排序,然后对他们根据大小重新赋值,当数的大小不对数据本身有影响,只有大小对其有影响时,可以使用离散化。

    离散化的标准姿势见 点这里

    然而蒟蒻并不会标准姿势,说说自己的方法:

    以本题为例,把所有的数据都存在nd结构体中

    void init()
    {
        for(int i = 1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d%s",&x,&y,c);
            nd[i].p = x;//数组开三倍,p表示临时变量。一倍存左端点。
            nd[i+m].p = y;//二倍存右端点。
            nd[i].num = i;//每一倍都要给他们打上编号,一会排序时后会乱。
            nd[i+m].num = i;if(c[0]=='e')
            {
                nd[i+m+m].odd = 0;//三倍存奇偶
            }else
            {
                nd[i+m+m].odd = 1;
            }
        }
    }

    读进来之后进行离散化。

    void discretization()
    {
        for(int i = 1;i<=2*m;i++)
        {
            if(nd[nd[i].num].l==-1)
            {
                nd[nd[i].num].l = cnt-1;
            }else 
            {
                nd[nd[i].num].r = cnt;
            }
            if(nd[i+1].p!=nd[i].p)
            {
                cnt++; //去重,不一样的时候再+1   
            }
        }
        for(int i = 1;i<=m;i++)
        {
            nd[i].odd = nd[i+m+m].odd;从三倍搬回原数组
        }
    }

    这样就离散完了。

    接下来就是带权并查集的操作。

    在合并和路径压缩的时候处理。

    思路就是将一个区间右面的点认左面的点为父亲,两端区间合并的时候,根据奇偶性判断,0表示偶数,1表示奇数(有点懒,具体0或1见代码)。

    int find(int x)
    {
        if(f[x]==x)
        {
            return f[x];
        }
        int fx = find(f[x]);
        g[x] = (g[f[x]]+g[x])%2;
        return f[x] = fx;
    }

    最后上总代码:

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    #define N 105550
    using namespace std;
    char c[20];
    ll n;
    int m;
    int cnt = 1;
    struct node
    {
        int l;
        int r;
        int num;
        int odd;
        int p;
    }nd[N+N+N];
    int f[N];
    int g[N];
    int cmp(node a,node b)
    {
        return a.p < b.p;
    }
    void init()
    {
        for(int i = 1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d%s",&x,&y,c);
            nd[i].p = x;
            nd[i+m].p = y;
            nd[i].num = i;
            nd[i+m].num = i;
            nd[i].l = -1;
            nd[i+m].l = -1;
            if(c[0]=='e')
            {
                nd[i+m+m].odd = 0;
            }else
            {
                nd[i+m+m].odd = 1;
            }
        }
    }
    void discretization()
    {
        for(int i = 1;i<=2*m;i++)
        {
            if(nd[nd[i].num].l==-1)
            {
                nd[nd[i].num].l = cnt-1;
            }else 
            {
                nd[nd[i].num].r = cnt;
            }
            if(nd[i+1].p!=nd[i].p)
            {
                cnt++;    
            }
        }
        for(int i = 1;i<=m;i++)
        {
            nd[i].odd = nd[i+m+m].odd;
        }
    }
    int find(int x)
    {
        if(f[x]==x)
        {
            return f[x];
        }
        int fx = find(f[x]);
        g[x] = (g[f[x]]+g[x])%2;
        return f[x] = fx;
    }
    int ans;
    bool flag;
    void uion(int x,int y,int i)
    {
        int fx = find(x);
        int fy = find(y);
        if(fx==fy)
        {
            if((nd[i].odd==1&&g[x]==g[y])||(nd[i].odd==0&&g[x]!=g[y]))
            {
                ans = i-1;
                flag = 1;
                return ;
            }
            find(y);
            find(x);
        }else
        {
            f[fy] = fx;
            g[fy] = (g[x]+g[y]+nd[i].odd)%2;
            find(x);
            find(y);        
        }
    }
    void solve()
    {
        for(int i = 1;i<=cnt;i++)
        {
            f[i] = i;
        }
        for(int i = 1;i<=m;i++)
        {
            int l = nd[i].l;
            int r = nd[i].r;
            uion(l,r,i);
            if(flag==1)
            {
                printf("%d
    ",ans);
                return ;
            }
        }
        printf("%d
    ",m);
    }
    int main()
    {
        scanf("%lld",&n);
        scanf("%d",&m);
        init();
        sort(nd+1,nd+1+m+m,cmp);
        discretization();
        solve();
        return 0;
    }
  • 相关阅读:
    脑机接口不断迎来重大突破,“思想钢印”还会远吗?
    ICLR 2020 | 神经网络架构搜索(NAS)论文推荐
    人工智能理解常识的数十年挑战,如何让 AI 不再“智障”?
    You Are All Excellent 排序
    sort
    sort
    绝对值排序
    绝对值排序
    排序
    排序
  • 原文地址:https://www.cnblogs.com/lizitong/p/10064673.html
Copyright © 2011-2022 走看看