BZOJ3898 : 打的士
设$f_i$表示选择的答案区间左端点为$i$时,区间长度最小是多少。
那么每来一批人的时候,设$nxt$为$i$右边最近的一个可行决策,则$f_i=\max(f_i,nxt-i)$。
注意到$f$的形式是一条条斜率为$-1$的线段,且截距单调不下降,故每次修改可以转化为对截距的区间赋值。
用线段树维护$f$,对于一个区间,如果无法覆盖最左端,则返回,如果可以覆盖最右端,则打标记,否则暴力递归左右儿子。
时间复杂度$O(n\log 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\n",x); } return 0; }