zoukankan      html  css  js  c++  java
  • 【bzoj1594】猜数游戏

    1594: [Usaco2008 Jan]猜数游戏

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 556  Solved: 225

    Description

    为了提高自己低得可怜的智商,奶牛们设计了一个新的猜数游戏,来锻炼她们的逻辑推理能力。 游戏开始前,一头指定的奶牛会在牛棚后面摆N(1 <= N<= 1,000,000)堆干草,每堆有若干捆,并且没有哪两堆中的草一样多。所有草堆排成一条直线,从左到右依次按1..N编号,每堆中草的捆数在1..1,000,000,000之间。 然后,游戏开始。另一头参与游戏的奶牛会问那头摆干草的奶牛 Q(1 <= Q <= 25,000)个问题,问题的格式如下: 编号为Ql..Qh(1 <= Ql <= Qh <= N)的草堆中,最小的那堆里有多少捆草? 对于每个问题,摆干草的奶牛回答一个数字A,但或许是不想让提问的奶牛那么容易地得到答案,又或许是她自己可能记错每堆中干草的捆数,总之,她的回答不保证是正确的。 请你帮助提问的奶牛判断一下,摆干草的奶牛的回答是否有自相矛盾之处。

    Input

    * 第1行: 2个用空格隔开的整数:N 和 Q

    * 第2..Q+1行: 每行为3个用空格隔开的整数Ql、Qh、A,描述了一个问题以及它 对应的回答

    Output

    * 第1行: 如果摆干草的奶牛有可能完全正确地回答了这些问题(也就是说,能 找到一种使得所有回答都合理的摆放干草的方法),输出0,否则输出 1个1..Q中的数,表示这个问题的答案与它之前的那些回答有冲突之处

    Sample Input

    20 4
    1 10 7
    5 19 7
    3 12 8
    11 15 12

    输入说明:

    编号为1..10的草堆中,最小的那堆里有7捆草,编号为5..19的草堆中同样
    如此;编号为3..12的草堆中最小的堆里是8捆草,11..15堆中的最小的堆里是12
    捆。

    Sample Output

    3

    输出说明:

    对于第3个问题“3 12”的回答“8”与前面两个回答冲突。因为每堆中草的
    捆数唯一,从前两个回答中我们能推断出,编号为5..10的干草堆中最小的那堆
    里有7捆干草。很显然,第3个问题的回答与这个推断冲突。

    HINT

    注意:如果有冲突出现输出一个数m,使得前M-1个命题不冲突。

    试题分析:首先要确定在什么情况下会出现矛盾:

          1.当存在一个(x1,y1,r)与另一个三元组(x,y,r)两个区间不相交时不存在解

          2.当存在一个(x1,y1,r1)与另一个三元组(x,y,r)中,r1>r,[x1,y1]包括[x,y],那么显然此情况不合法。

         第一个判断只需要顺次判断记录一个交集一个并集即可,第二个判断线段树维护。

         此时会发现一个问题,顺次修改并不能判断1在哪里出现矛盾或判断在2出现矛盾。

         这样我们就需要考虑二分一个答案,然后检验这个答案以及之前是否会出现矛盾。

         先离散化一下r,然后对于每个r求出其询问的交集和并集。

         然后我们就可以知道判断1只需要使用交集判断,如果一个r的询问和之前r询问的交集没有相交,那么就矛盾。

         对于判断2,从Q~1枚举r,我们的线段树只需要维护一下两个操作:

          1.查询区间与运算

          2.将一段区间置为1

         这是很好维护的,然后注意一点,取区间与需要判断的是交集,而询问中(x,y,r)相当于声明[x,y]这段区间的最小值已经是r了,那么就需要在线段树中将[x并,y并](对于询问答案r的)这一段区间置为1,而不是取交集置为1。

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    using namespace std;
    inline int read(){
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int MAXN = 1000001;
    const int INF = 999999;
    int N,Q;
    struct data{
        int x,y,r;
        int id;
    }a[MAXN+1];
    int ans; int P[MAXN+1],cnt;
    bool cmp(data a,data b){
        return a.r<b.r;
    }
    struct row{
        int x,y;
        int x1,y1;
    }t[MAXN+1];
    int tr[MAXN*4+1];
    int col[MAXN*4+1];
    
    int mint(int a,int b){
        return min((a==INF?-INF:a),(b==INF?-INF:b));
    }
    void Lazy_tage(int l,int r,int rt){
        if(!col[rt]) return ;
        tr[rt*2]=1; tr[rt*2+1]=1; tr[rt]=1;
        col[rt*2]=1; col[rt*2+1]=1;
        col[rt]=0;
    }
    int Min(int rt,int l,int r,int L,int R){
        if(L<=l&&R>=r){
            return tr[rt];
        }
        Lazy_tage(l,r,rt);
        int mid=(l+r)>>1,ans=1;
        if(mid>=L) ans=ans&Min(rt*2,l,mid,L,R);
        if(mid<R) ans=ans&Min(rt*2+1,mid+1,r,L,R);
        return ans;
    }
    void Add(int rt,int l,int r,int L,int R){
        if(L<=l&&R>=r){
            tr[rt]=1;
            col[rt]=1;
            return ;
        }
        Lazy_tage(l,r,rt);
        int mid=(l+r)>>1;
        if(mid>=L) Add(rt*2,l,mid,L,R);
        if(mid<R) Add(rt*2+1,mid+1,r,L,R);
        tr[rt]=tr[rt*2]&tr[rt*2+1];
        return ;
    }
    
    bool check(int k){
        memset(tr,0,sizeof(tr));
        memset(col,0,sizeof(col));
        for(int i=1;i<=Q;i++)
            t[i].x=t[i].y=-1;
        for(int i=1;i<=Q;i++){
            if(a[i].id>k) continue;
            if(t[a[i].r].x==-1){
                t[a[i].r].x=a[i].x;//x,y为并集
                t[a[i].r].y=a[i].y;
                t[a[i].r].x1=a[i].x;//x1,y1为交集
                t[a[i].r].y1=a[i].y;
            }
            else{
                if(a[i].x>t[a[i].r].y||a[i].y<t[a[i].r].x) return false;
                t[a[i].r].x=max(t[a[i].r].x,a[i].x);
                t[a[i].r].y=min(t[a[i].r].y,a[i].y);
                t[a[i].r].x1=min(t[a[i].r].x1,a[i].x);
                t[a[i].r].y1=max(t[a[i].r].y1,a[i].y);
            }
        }
        for(int i=Q;i>=1;i--){
            if(t[i].x!=-1){
                int op=Min(1,1,N,t[i].x,t[i].y);//查询r的并集,只有并集中才可能出现r
                if(op==1) return false;
                Add(1,1,N,t[i].x1,t[i].y1);//这里需要将交集加上
            }
        }
        return true;
    }
    
    int main(){
        N=read(),Q=read();
        for(int i=1;i<=Q;i++){
            a[i].x=read(); a[i].y=read();
            a[i].r=read(); P[++cnt]=a[i].r;
            a[i].id=i;
        }
        sort(P+1,P+cnt+1);
        for(int i=1;i<=Q;i++) a[i].r=lower_bound(P+1,P+cnt+1,a[i].r)-P;//离散化r
        sort(a+1,a+Q+1,cmp);
        int l=1,r=Q;
        while(l<=r){
            int mid=(l+r)>>1;
            if(check(mid)) ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d
    ",(ans+1)%(Q+1));
    }
    

      

     
  • 相关阅读:
    输入和输出--java的NIO
    Java的NIO
    Java的nio
    输入和输出--java序列化机制
    输入和输出--javase中的路径
    输入和输出--重定向标准输入和输出
    输入和输出--RandomAccessFile类
    输入和输出--IO流
    输入和输出--File类
    无废话XML--DOM4J
  • 原文地址:https://www.cnblogs.com/wxjor/p/7722987.html
Copyright © 2011-2022 走看看