zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    JavaScript 数组操作函数--转载+格式整理
    Python之__str__类的特殊方法
    Django 模板层(Template)
    jquery基础
    Django基础(web框架)
    前端基础之JavaScript对象
    前端基础之JavaScript
    MySQL数据库之索引
    MySQL数据库之多表查询
    MySQL 数据库之单表查询
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/10357635.html
Copyright © 2011-2022 走看看