zoukankan      html  css  js  c++  java
  • BZOJ1795 : [Ioi2008]Pyramid Base 金字塔地基

    1.$B>0$

    二分答案,然后扫描线,线段树维护某个点作为左下角时的费用的最小值,支持区间加。

    时间复杂度$O(nlog^2n)$。

    2.$B=0$

    枚举左边界,则最优右边界可以通过双指针求出。

    用线段树维护左右边界之间最长的竖着的空的连续段的长度。

    找到最大的连续段长度$geq$左右边界距离的位置,此时的距离就是答案。

    时间复杂度$O(nlog n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,B,P;
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    namespace BinarySearch{
    const int N=30010,M=2100000;
    int i,j,l,r,mid,ans,ce,v[M],tag[M];
    struct O{int a,b,c,d,p;}a[N];
    struct E{int x,l,r,p;E(){}E(int _x,int _l,int _r,int _p){x=_x,l=_l,r=_r,p=_p;}}e[N*2];
    inline bool cmp(const E&a,const E&b){return a.x<b.x;}
    void build(int x,int a,int b){
      v[x]=tag[x]=0;
      if(a==b)return;
      int mid=(a+b)>>1;
      build(x<<1,a,mid),build(x<<1|1,mid+1,b);
    }
    inline void add1(int x,int p){v[x]+=p;tag[x]+=p;}
    void add(int x,int a,int b,int c,int d,int p){
      if(c<=a&&b<=d){add1(x,p);return;}
      if(tag[x])add1(x<<1,tag[x]),add1(x<<1|1,tag[x]),tag[x]=0;
      int mid=(a+b)>>1;
      if(c<=mid)add(x<<1,a,mid,c,d,p);
      if(d>mid)add(x<<1|1,mid+1,b,c,d,p);
      v[x]=min(v[x<<1],v[x<<1|1]);
    }
    inline bool check(int mid){
      for(ce=0,i=1;i<=P;i++){
        int A=a[i].a-mid+1,B=a[i].b-mid+1,C=a[i].c,D=a[i].d;
        A=max(A,1),B=max(B,1),C=min(C,n-mid+1),D=min(D,m-mid+1);
        if(A<=C&&B<=D)e[++ce]=E(A,B,D,a[i].p),e[++ce]=E(C+1,B,D,-a[i].p);
      }
      sort(e+1,e+ce+1,cmp);
      build(1,1,m-mid+1);
      for(i=j=1;i<=n-mid+1;i++){
        while(j<=ce&&e[j].x<=i)add(1,1,m-mid+1,e[j].l,e[j].r,e[j].p),j++;
        if(v[1]<=B)return 1;
      }
      return 0;
    }
    void solve(){
      for(i=1;i<=P;i++)read(a[i].a),read(a[i].b),read(a[i].c),read(a[i].d),read(a[i].p);
      l=1,r=min(n,m);
      while(l<=r)if(check(mid=(l+r)>>1))l=(ans=mid)+1;else r=mid-1;
      printf("%d",ans);
    }
    }
    namespace Sweep{
    const int N=1000010,M=2100000;
    int A,B,C,D,i,j,k,ans,gi[N],gd[N],v[N],w[N],nxt[N],ed;
    int tag[M],len[M],vl[M],vr[M],vm[M];
    inline void add(int&x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=x;x=ed;}
    void build(int x,int a,int b){
      len[x]=vl[x]=vr[x]=vm[x]=b-a+1;
      if(a==b)return;
      int mid=(a+b)>>1;
      build(x<<1,a,mid),build(x<<1|1,mid+1,b);
    }
    inline void up(int x){
      if(tag[x]){vl[x]=vr[x]=vm[x]=0;return;}
      if(len[x]==1){vl[x]=vr[x]=vm[x]=1;return;}
      vl[x]=vl[x<<1];
      if(vl[x<<1]==len[x<<1])vl[x]+=vl[x<<1|1];
      vr[x]=vr[x<<1|1];
      if(vr[x<<1|1]==len[x<<1|1])vr[x]+=vr[x<<1];
      vm[x]=max(max(vm[x<<1],vm[x<<1|1]),vr[x<<1]+vl[x<<1|1]);
    }
    void add(int x,int a,int b,int c,int d,int p){
      if(c<=a&&b<=d){tag[x]+=p;up(x);return;}
      int mid=(a+b)>>1;
      if(c<=mid)add(x<<1,a,mid,c,d,p);
      if(d>mid)add(x<<1|1,mid+1,b,c,d,p);
      up(x);
    }
    void solve(){
      while(P--)read(A),read(B),read(C),read(D),read(k),add(gi[A],B,D),add(gd[C],B,D);
      build(1,1,m);
      for(i=1;i<=n;i++){
        for(k=gd[i-1];k;k=nxt[k])add(1,1,m,v[k],w[k],-1);
        while(vm[1]>=j-i+1&&j<=n)for(k=gi[++j];k;k=nxt[k])add(1,1,m,v[k],w[k],1);
        ans=max(ans,j-i);
      }
      printf("%d",ans);
    }
    }
    int main(){
      read(n),read(m),read(B),read(P);
      if(B)BinarySearch::solve();else Sweep::solve();
      return 0;
    }
    

      

  • 相关阅读:
    头文件stdio与stdlib.h的区别
    宝塔利用git+ webhooks 实现git更新远程同步Linux服务器
    Linux源码安装步骤
    Promise.all和Promise.race区别,和使用场景
    vue显示富文本
    Js实现将html页面或div生成图片
    JS
    关于Swiper和vue数据顺序加载问题处理
    php 数据库备份(可用作定时任务)
    js async await 终极异步解决方案
  • 原文地址:https://www.cnblogs.com/clrs97/p/5648487.html
Copyright © 2011-2022 走看看