zoukankan      html  css  js  c++  java
  • usaco 猜数游戏

    Description

    为了提高智商,锻炼思维能力,奶牛设计了一个猜数游戏。游戏开始前,贝西会在牛棚后面摆上N个数字。所有数字排成一条直线,按次序从1到N编号。每个数字在1到10^9之间,没有两个数字是一样的。

    游戏开始后,其他奶牛将会轮流询问贝西Q个问题,每个问题的格式都是一样的:

    “位置在Ql到Qr的数字中,最小的数字是多少?”

    对每个问题,贝西都会回答一个数字A,不过,她的回答可能是不正确的。请你帮助其他奶牛判断一下,贝西从哪里开始已经出现矛盾了。

    Input Format

    第一行:两个用空格分开的整数:N和Q,1 ≤ N ≤ 106,1 ≤ Q ≤ 25000

    第二行到第Q + 1行:每行三个用空格分开的整数,Ql,Qr和A,表示一个查询,1 ≤ Ql ≤ Qh ≤ N

    Output Format

    第一行:如果完全没有矛盾,输出0,否则输出最先造成矛盾的查询编号

    ------------------------------------------------------------------

    正解 = 找规律+并查集

    Orz 神大胖指导。
    正如题目所说,这 n 个数中不会有重复的,
       因此对于相同的值的询问如果不存在交集便是一个矛盾,
       如果存在交集,那这个数必然就在这个区间中,
       但如果之前的询问已覆盖了这个区间
               A:如果询问值比该数小,这是种合法情况,
               因为之前的询问还能覆盖该区间外的地方,
               B:如果询问值比该数大,显然矛盾.
    得到一个判断一段查询是否合法的算法:
       将所给的询问按数值排序(从大到小),
       对于同个数值进行合并操作, 
       如不存在交集 =>存在矛盾
       否则对询问交集中是否已被在比该数值大的值所覆盖,
       由于已经按从小到大排过序,如果交集中有值必然比该数值大
       所以,如果区间中不存在未覆盖的位置 = > 存在矛盾
       否则说明至此未产生矛盾:
       对于该同数值的询问的并集中未覆盖的部分进行覆盖
    如果进行完所有操作未发现矛盾,则该区间不存在矛盾.
    由于仅对区间中的未覆盖的位置进行查询及修改,可以用并查集进行加速.
    在上述算法的基础上,我们可以对矛盾区间进行二分查找,不难得到答案.
    Ps.笔者打的递归并查集爆(W)栈(T)了(F),不能忍,该模拟栈了- =.
    代码如下:

     1 #include<cstring>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<string>
     5 #include<iostream>
     6 #include<queue>
     7 #define INF 99999999
     8 #define min(X,Y) if(X>Y) X=Y
     9 #define max(X,Y) if(X<Y) X=Y
    10 #define N 1000122
    11 #define M 25022
    12 using namespace std;
    13 int f[N],n,Q,mid,ans;
    14 int q[N];
    15 struct Query{
    16     int l,r,v;
    17 }a[M],b[M];
    18 bool cmp(const Query&X,const Query&Y){
    19     return X.v>Y.v;
    20 }
    21 int find(int now){
    22     int tail=0;
    23     q[++tail]=now;
    24     while(1){
    25      now=q[tail];
    26      if(now==f[now]) break; 
    27      q[++tail]=f[now];
    28     }
    29     while(tail) f[q[tail--]]=now;
    30     return now;
    31 }
    32 bool check(){
    33     for(int i=1;i<=n+3;i++) f[i]=i;
    34     memcpy(b,a,sizeof(Query)*(mid+1));
    35     sort(b+1,b+1+mid,cmp);
    36     for(int i=1;i<=mid;i++){
    37         int Min=b[i].l,Max=b[i].r;
    38         int L=b[i].l  ,R=b[i].r;
    39         for(;i<=mid&&b[i].v==b[i+1].v;){
    40             ++i;
    41             min(Min,b[i].l);
    42             max(Max,b[i].r);
    43             if(L>b[i].r||R<b[i].l) return false ;
    44             max(L,b[i].l);
    45             min(R,b[i].r);    
    46         }
    47         if(find(L)>R) return false ;
    48         for(int k=find(Min);k<=Max;k=f[k])
    49          f[k]=find(k+1);
    50     }
    51     return true; 
    52 }
    53 int main(){
    54     scanf("%d%d",&n,&Q);
    55     for(int i=1;i<=Q;i++)
    56         scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].v);
    57     int Le=1,Ri=Q;
    58     while(Ri>=Le){
    59         mid=(Le+Ri)>>1;
    60         if(!check()){
    61             Ri=mid-1; 
    62             ans=mid;
    63         } else Le=mid+1;
    64     }
    65     printf("%d",ans); 
    66 }
    View Code
  • 相关阅读:
    Python模块:shutil、序列化(json&pickle&shelve)、xml
    IO流----操作文件的9种方法代码实现
    IO流--字符流与字节流--File类常用功能
    常用集合之间的关系
    HashMap 集合的遍历
    java代码实现ftp服务器的文件上传和下载
    java中数组、集合、字符串之间的转换,以及用加强for循环遍历
    java中的正则表达式
    使用Calender类获取系统时间和时间和运算
    产生任意区间的随机数
  • 原文地址:https://www.cnblogs.com/Blacko/p/3383275.html
Copyright © 2011-2022 走看看