• BZOJ3898 : 打的士


    设$f_i$表示选择的答案区间左端点为$i$时,区间长度最小是多少。

    那么每来一批人的时候,设$nxt$为$i$右边最近的一个可行决策,则$f_i=max(f_i,nxt-i)$。

    注意到$f$的形式是一条条斜率为$-1$的线段,且截距单调不下降,故每次修改可以转化为对截距的区间赋值。

    用线段树维护$f$,对于一个区间,如果无法覆盖最左端,则返回,如果可以覆盖最右端,则打标记,否则暴力递归左右儿子。

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

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=1000010,M=2100000,inf=2000000010;
    int n,i,j,x,y,q[N][2],st[N],en[N],m,b[N],e[N],k,a[N],l[M],r[M],v[M],tag[M];
    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';}
    inline int lower(int x){
      int l=1,r=m,mid,t;
      while(l<=r)if(e[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
      return t;
    }
    inline void tag1(int x,int a,int b,int p){
      l[x]=p-e[a];
      v[x]=r[x]=p-e[b];
      tag[x]=p;
    }
    inline void pb(int x,int a,int b){
      if(tag[x]<0)return;
      int mid=(a+b)>>1;
      tag1(x<<1,a,mid,tag[x]);
      tag1(x<<1|1,mid+1,b,tag[x]);
      tag[x]=-1;
    }
    inline void up(int x){
      l[x]=l[x<<1];
      r[x]=r[x<<1|1];
      v[x]=min(v[x<<1],v[x<<1|1]);
    }
    void build(int x,int a,int b){
      tag[x]=-1;
      if(a==b)return;
      int mid=(a+b)>>1;
      build(x<<1,a,mid),build(x<<1|1,mid+1,b);
    }
    void change(int x,int a,int b,int c,int d,int p){
      if(c<=a&&b<=d){
        if(p-e[a]<=l[x])return;
        if(p-e[b]>r[x]){tag1(x,a,b,p);return;}
      }
      pb(x,a,b);
      int mid=(a+b)>>1;
      if(c<=mid)change(x<<1,a,mid,c,d,p);
      if(d>mid)change(x<<1|1,mid+1,b,c,d,p);
      up(x);
    }
    int ask(int x,int a,int b,int c,int d){
      if(c<=a&&b<=d)return v[x];
      pb(x,a,b);
      int mid=(a+b)>>1,t=inf;
      if(c<=mid)t=ask(x<<1,a,mid,c,d);
      if(d>mid)t=min(t,ask(x<<1|1,mid+1,b,c,d));
      return up(x),t;
    }
    int main(){
      read(n);
      for(i=1;i<=n;i++){
        char ch;
        while((ch=getchar())!='C'&&ch!='Q');
        q[i][0]=ch=='C';read(x);
        if(ch=='C'){
          st[i]=m+1,en[i]=m+x;
          while(x--)read(y),b[++m]=y;
        }else q[i][1]=b[++m]=x;
      }
      for(i=1;i<=m;i++)e[i]=b[i];
      sort(e+1,e+m+1);
      build(1,1,m);
      for(i=1;i<=n;i++)if(q[i][0]){
        k=0;
        for(j=st[i];j<=en[i];j++)a[++k]=lower(b[j]);
        sort(a+1,a+k+1);
        for(j=1;j<=k;j++)if(a[j]>a[j-1])change(1,1,m,a[j-1]+1,a[j],e[a[j]]);
        if(a[k]<m)change(1,1,m,a[k]+1,m,inf);
      }else{
        x=ask(1,1,m,lower(q[i][1]),m);
        if(x>1000000000)x=-1;
        printf("%d
    ",x);
      }
      return 0;
    }
    

      

  • 相关阅读:
    cmd 重启oracle服务
    删除父节点同时删除该节点上的所有子节点(oracle)
    安装Oracle提示OracleMTSRecoveryService 已经存在,解决方法
    扩展easyui treegrid 级联选择
    Jetson TX2 不同的工作模式
    CMake版本升级
    高斯混合背景模型运动目标检测
    Windows WSL 安装OpenCV
    C++实现队列
    图像的尺度描述
  • 原文地址:https://www.cnblogs.com/clrs97/p/5851880.html
Copyright © 2020-2023  润新知