zoukankan      html  css  js  c++  java
  • [bzoj1594] [Usaco2008 Jan]猜数游戏

      二分答案(二分没冲突的前Q-1个问题),用并查集判定(用法同bzoj 1576)

      假设一个询问区间[l,r],最小干草堆数目是A,我们可以得出[l,r]上的干草堆数目都>=A。

      二分出mid后,把1~mid个询问按照最小干草数量A降序排序。。如果这些询问的回答自相矛盾的话,就存在一个询问区间[l,r],它的每个位置都存在于之前的询问区间(指那些A值比当前A值大的区间)中。也就是说根据以前的询问我们得出[l,r]里面任何一堆干草数目都大于当前的A值,那就自相矛盾了。(注意如果多个区间A值相同的话就取交集。

      就变成判断一段区间是否已被完全覆盖。。那就可以上并查集了。fa[i]表示i点所在的被覆盖的区间的左端点。

      这样的话是O(nlogQ*alpha(n))的。。我们可以离散化一下。。因为只要知道当前区间中是否存在一个点没被覆盖过,所以只要从离散化后相邻两个值中多拿出一个点做代表就行了(前提是相邻的差值>1)。这样就只剩4*Q堆干草了。

      卡了半天常。。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 const int maxn=1000233;
     7 struct zs{
     8     int l,r,id,mn;
     9 }q[25003];
    10 int fa[100003],now[25003],map[50003],L[25003],R[25003],mp[100003];
    11 int j,k,n,m,l,r,mid,tot,premx,mnx,mny,mxx,mxy;
    12 bool flag;
    13 int ra;char rx;
    14 inline int read(){
    15     rx=getchar();ra=0;
    16     while(rx<'0'||rx>'9')rx=getchar();
    17     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
    18 }
    19 bool cmp(zs a,zs b){return a.mn>b.mn;}
    20 inline bool can(int x){
    21     register int i,j,k;now[0]=0;
    22     for(i=1;i<=m;i++)if(q[i].id<=x)L[++now[0]]=q[i].l,R[now[0]]=q[i].r,now[now[0]]=i;
    23     memset(fa,0,(premx+1)<<2);premx=0;
    24     for(i=1;i<=now[0];i=j+1){
    25         for(j=i;j<now[0]&&q[now[j+1]].mn==q[now[i]].mn;j++);
    26         mnx=mny=tot;mxx=mxy=0;
    27         for(k=i;k<=j;k++){
    28             if(L[k]<mnx)mnx=L[k];if(L[k]>mxx)mxx=L[k];if(R[k]<mny)mny=R[k];if(R[k]>mxy)mxy=R[k];
    29         }
    30         for(flag=0,k=mny;k>=mxx;k=fa[k]-1)
    31             if(!fa[k]){flag=1;break;}
    32         if(!flag)return 0;
    33         if(mxy>premx)premx=mxy;
    34         for(k=mxy;k>=mnx;k--)
    35             if(!fa[k])fa[k]=mnx;
    36             else{k=fa[k];if(k>=mnx)fa[k]=mnx;}
    37     }
    38     return 1;
    39 }
    40 inline int get(int x){
    41     l=1;r=tot;
    42     while(l<r){
    43         mid=(l+r+1)>>1;
    44         if(mp[mid]>x)r=mid-1;else l=mid;
    45     }return l;
    46 }
    47 int main(){
    48     register int i;
    49     n=read();m=read();tot=m<<1;
    50     for(i=1;i<=m;i++)q[i].l=map[i]=read(),q[i].r=map[i+m]=read(),q[i].mn=read(),q[i].id=i;
    51     sort(map+1,map+1+tot);int tmp=0;
    52     for(i=1;i<=tot;i++)if(map[i]!=map[i-1])map[++tmp]=map[i];tot=tmp;tmp=0;
    53     for(i=1;i<=tot;i++)if(map[i]+1<map[i+1])mp[++tmp]=map[i],mp[++tmp]=map[i]+1;else mp[++tmp]=map[i];
    54     tot=tmp;
    55     for(i=1;i<=m;i++)q[i].l=get(q[i].l),q[i].r=get(q[i].r);
    56     sort(q+1,q+1+m,cmp);
    57     l=1;r=m;
    58     while(l<r){
    59         mid=(l+r+1)>>1;
    60         if(can(mid))l=mid;else r=mid-1;
    61     }
    62     if(l==m)puts("0");else printf("%d
    ",l+1);
    63     return 0;
    64 }
    View Code

     UPD:妈呀之前有个地方大和小打反了>_<..已更正

     UPD2: 还需要特判 值不够用的情况..因为数字互不相同&上限是10^9。

                  一个询问(L,R,A)意味着这个区间里有R-L+1个>=A的数...数据(可能出题人也)没有考虑到这部分..

                  正常版本见51nod1336。有个做法是二分图匹配,不过复杂度感人。

  • 相关阅读:
    SharePoint 2010 At Work--SharePoint 2010 Tab Page 创建选项卡页面
    SharePoint At Work----Hyperlinks in the Data View Web Part
    SharePoint At Work----SharePoint Data View Web Part
    SharePoint 2010 品牌化和自定义--母版页
    面对复杂的或者高并发的或者海量数据的问题
    提升算力的程序设计
    关于方案,关于设计,关于思考
    关于测试
    数据资源管理程序的功能以及设计的总结
    如何做软件设计
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5074066.html
Copyright © 2011-2022 走看看