设第$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$。
所以$ansgeqmax(a[i]-f[i])=max(a[i]-a[j]-ans-(i-j) imes len)$,
即$ansgeqfrac{max(a[i]-a[j]-(i-j) imes len)}{2}(lleq jleq ileq r)$。
2. 可以覆盖位置$0$
即$f[l]leq 0$,所以$a[i]+ans-(i-l) imes lenleq 0$,
故$ansgeqmax(a[i]-(i-l) imes len)$。
3. 可以覆盖位置$all$
即$f[r]geq all-len$,所以$a[i]+ans+(r-i) imes lengeq all-len$,
故$ansgeqmax(all-len-a[i]-(r-i) imes len)$。
对于环的情况,只需要把区间复制一份,那么只需要满足条件1就能保证没有死角:
即$ansgeqfrac{max(a[i]-a[j]-(i-j) imes len)}{2}(lleq jleq ileq r)$,
且$ansgeqfrac{max(a[i]+all-a[j]-(r-l+1-(j-i)) imes len)}{2}(lleq i<jleq r)$。
以上所有信息都可以通过线段树进行区间合并,时间复杂度$O(mlog 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
",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;
}