• p3634 [APIO2012]守卫


    传送门

    分析

    1.先预处理出不被0覆盖的点,然后对每个点处理出在它左边离他最近的点和在他右边理他最近的点。

    2.对于每个至少存在一个忍者的区间,先将它左右边界处理为不被0所覆盖。排序后将包含其他区间的区间去除。

    3.贪心求出前i个区间最小忍者数和后i个区间最小忍者数。

    4.我们知道对于一个区间除了点R[i]之外最优的点就是R[i]-1,所以我们二分一个右端点小于R[i]-1的最靠右区间k1和一个左端点大于R[i]-1的最靠左区间k2,如果f[k1]+g[k2]+1>k则代表点R[i]必选

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<ctime>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    struct node {
        int le,ri,k;
    };
    node d[110000];
    int a[110000],b[110000],pos[110000],sum[110000],cnt,tot,n,m,k;
    int L[110000],R[110000],f[110000],g[110000];
    inline bool cmp(const node x,const node y){
        return x.le<y.le;
    }
    int main(){
        int i,j;
        scanf("%d%d%d",&n,&k,&m);
        for(i=1;i<=m;i++){
          scanf("%d%d%d",&d[i].le,&d[i].ri,&d[i].k);
          if(!d[i].k){
              sum[d[i].le]++;
              sum[d[i].ri+1]--;
          }
        }
        for(i=1;i<=n;i++){
          sum[i]+=sum[i-1];
          if(!sum[i]){
              pos[++tot]=i;
              a[i]=b[i]=tot;
          }
        }
        if(tot==k){
          for(i=1;i<=tot;i++)
            printf("%d
    ",pos[i]);
          return 0;
        }
        a[n+1]=n+1;
        for(i=n;i>0;i--)
          if(!a[i])a[i]=a[i+1];
        for(i=1;i<=n;i++)
          if(!b[i])b[i]=b[i-1];
        for(i=1;i<=m;i++)
          if(d[i].k){
              d[++cnt].le=a[d[i].le];
              d[cnt].ri=b[d[i].ri];
          }
        m=cnt;
        sort(d+1,d+m+1,cmp);
        cnt=0;
        for(i=1;i<=m;i++){
          while(cnt&&d[i].le>=L[cnt]&&d[i].ri<=R[cnt])--cnt;
          L[++cnt]=d[i].le;
          R[cnt]=d[i].ri;
        }
        int l=n+1,r=0;
        for(i=1;i<=cnt;i++){
          if(L[i]>r)f[i]=f[i-1]+1,r=R[i];
            else f[i]=f[i-1];
        }
        for(i=cnt;i>0;i--){
          if(R[i]<l)g[i]=g[i+1]+1,l=L[i];
            else g[i]=g[i+1];
        }
        int ok=0;
        for(i=1;i<=cnt;i++){
          if(f[i]==f[i-1])continue;
          if(L[i]==R[i]){
              printf("%d
    ",pos[R[i]]);
              ok=1;
              continue;
          }
          int l=0,r=cnt+1,x=0,y=cnt+1;
          while(r-l>1){
              int mid=(l+r)>>1;
              if(R[mid]<R[i]-1)x=mid,l=mid;
                else r=mid;
          }
          l=0,r=cnt+1;
          while(r-l>1){
              int mid=(l+r)>>1;
              if(L[mid]>R[i]-1)y=mid,r=mid;
                else l=mid;
          }
          if(f[x]+g[y]+1>k){
              printf("%d
    ",pos[R[i]]);
              ok=1;
          }
        }
        if(!ok)puts("-1");
        return 0;
    }
  • 相关阅读:
    Android——另外一种增删查改的方式(ContentProvider常用)
    VS2012下基于Glut OpenGL glScissor示例程序:
    JAXP的SAX解析
    38岁老男孩个人建站方向求教
    [置顶] 某大型银行深化系统技术方案之十三:服务层之服务接口模式
    比特币人必知术语
    ok6410 u-boot-2012.04.01移植二修改源码支持单板
    最近修bug的一点感悟
    小智慧24
    redis beforesleep
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/10357635.html
Copyright © 2020-2023  润新知