BZOJ2567 : 篱笆
设第$i$个区间的左端点为$a[i]$,区间长度为$len$,要覆盖的部分的长度为$all$,因为区间左端点递增,所以最优方案中它们的位置仍然递增。
对于链的情况,要满足三个条件:
1. 区间$i$可以接上区间$i-1$
设$f[i]$表示最优解中第$i$个区间左端点的位置,则$f[i]=\min(f[i-1]+len,a[i]+ans)$且$f[i]\geq a[i]-ans$。
所以$ans\geq\max(a[i]-f[i])=\max(a[i]-a[j]-ans-(i-j)\times len)$,
即$ans\geq\frac{\max(a[i]-a[j]-(i-j)\times len)}{2}(l\leq j\leq i\leq r)$。
2. 可以覆盖位置$0$
即$f[l]\leq 0$,所以$a[i]+ans-(i-l)\times len\leq 0$,
故$ans\geq\max(a[i]-(i-l)\times len)$。
3. 可以覆盖位置$all$
即$f[r]\geq all-len$,所以$a[i]+ans+(r-i)\times len\geq all-len$,
故$ans\geq\max(all-len-a[i]-(r-i)\times len)$。
对于环的情况,只需要把区间复制一份,那么只需要满足条件1就能保证没有死角:
即$ans\geq\frac{\max(a[i]-a[j]-(i-j)\times len)}{2}(l\leq j\leq i\leq r)$,
且$ans\geq\frac{\max(a[i]+all-a[j]-(r-l+1-(j-i))\times len)}{2}(l\leq i<j\leq r)$。
以上所有信息都可以通过线段树进行区间合并,时间复杂度$O(m\log n)$。
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=120010,M=262150,BUF=30000000; const ll inf=1LL<<60; int T,n,m,type,i,x,y;ll all,r,len,a[N],b[N],ans;bool flag;char Buf[BUF],*buf=Buf; struct P{ ll v,w,ma,mi; void set(ll b){v=w=0,ma=mi=b;} P operator+(const P&b){ P c; c.v=max(max(v,b.v),b.ma-mi); c.w=max(max(w,b.w),ma-b.mi); c.ma=max(ma,b.ma); c.mi=min(mi,b.mi); return c; } }v[M],val; inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;} inline void read(ll&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;} void build(int x,int a,int b){ if(a==b){v[x].set(::b[a]);return;} int mid=(a+b)>>1; build(x<<1,a,mid),build(x<<1|1,mid+1,b); v[x]=v[x<<1]+v[x<<1|1]; } void ask(int x,int a,int b,int c,int d){ if(c<=a&&b<=d){ if(!flag)val=v[x];else val=val+v[x]; flag=1; return; } int mid=(a+b)>>1; if(c<=mid)ask(x<<1,a,mid,c,d); if(d>mid)ask(x<<1|1,mid+1,b,c,d); } inline void query(int x,int y){ flag=0; ask(1,1,n,x,y); if(type==1){ ans=val.v; ans=max(ans,(val.ma+len*x)*2); ans=max(ans,(all-len-val.mi-len*y)*2); }else ans=max(val.v,val.w-len*(y-x+1)+all); printf("%lld.%lld0000\n",ans/2,ans%2*5); } int main(){ fread(Buf,1,BUF,stdin);read(T); while(T--){ read(n),read(all),read(r),read(m),read(type); len=r*2; for(i=1;i<=n;i++)read(a[i]),a[i]-=r,b[i]=a[i]-len*i; build(1,1,n); query(1,n); while(m--)read(x),read(y),query(x,y); } return 0; }