题目大意:$N$ 件物品摆成一排,给每个物品定义两个属性 $A$ 和$ B$,两件物品的 差异度 定义为它们两种属性的差的绝对值中较大的一个。如果要求出一些物品的差异度,我们先定义一个 理想物品,使它与这些物品中每个物品的差异度的和最小,这些物品的差异度就是这个最小的和。给定$ N$ 个物品和Q组询问,询问从 $L $到 $R$ 的物品差异度为多少。
我们设物品$i$和物品$j$之间的差异度为$D$,则
$D=max\{|A_i-A_j|,|B_i-B_j|\}$
$=max\{A_i-A_j,A_j-A_i,B_i-B_j,B_j-B_i\}$
我们令$X_i=A_i+B_i,X_j=A_j+B_j,Y_i=A_i-B_i,Y_j=A_j-B_j$。
则有$D=max\{(X_i-X_j)+(Y_i-Y_j),(X_i-X_j)-(Y_i-Y_j),-(X_i-X_j)+(Y_i-Y_j),-(X_i-X_j)-(Y_i-Y_j)\}$
简单化简后,$D=|X_i-X_j|+|Y_i-Y_j|$。
对于每一件物品,我们求出其对应的$X$值和$Y$值。
我们建两棵主席树,分别维护$X$值和$Y$值。
查询一个区间时,我们在两棵主席树上分别查询区间中位数,然后随便维护一下就行了。
时间复杂度:$O(n\log\ n)$。
#include<bits/stdc++.h>
#define M 100005
#define L long long
#define INF (2e9)
using namespace std; L n,q,A[M]={},B[M]={}; L lc[M*]={},rc[M*]={},siz[M*]={},cnt=; L sum[M*]={};
L root1[M]={},root2[M]={};
void add(L &x,L l,L r,L now){
cnt++; lc[cnt]=lc[x]; rc[cnt]=rc[x];
siz[cnt]=siz[x]+; sum[cnt]=sum[x]+now; x=cnt;
if(l==r) return; L mid=(l+r)>>;
if(now<=mid) add(lc[x],l,mid,now);
else add(rc[x],mid+,r,now);
}
L getkth(L x,L y,L l,L r,L k){
if(l==r) return l;
L mid=(l+r)>>;
if(siz[lc[y]]-siz[lc[x]]<k) return getkth(rc[x],rc[y],mid+,r,k-(siz[lc[y]]-siz[lc[x]]));
return getkth(lc[x],lc[y],l,mid,k);
}
L getsum(L x,L l,L r,L ll,L rr){
if(ll<=l&&r<=rr) return sum[x];
L mid=(l+r)>>,res=;
if(ll<=mid) res+=getsum(lc[x],l,mid,ll,rr);
if(mid<rr) res+=getsum(rc[x],mid+,r,ll,rr);
return res;
} main(){
scanf("%lld%lld",&n,&q);
for(L i=;i<=n;i++) scanf("%lld",A+i);
for(L i=;i<=n;i++) scanf("%lld",B+i);
for(L i=;i<=n;i++){
L upd1=A[i]+B[i],upd2=A[i]-B[i];
root1[i]=root1[i-]; root2[i]=root2[i-];
add(root1[i],-INF,INF,upd1);
add(root2[i],-INF,INF,upd2);
}
while(q--){
L l,r,k,h;L res=,mid; scanf("%lld%lld",&l,&r);
h=(r-l)/+; mid=(l+r)>>;
k=getkth(root1[l-],root1[r],-INF,INF,h);
res+=getsum(root1[r],-INF,INF,k,INF)-getsum(root1[l-],-INF,INF,k,INF);
res-=k*(r-mid+);
res+=(mid-l)*k;
res-=getsum(root1[r],-INF,INF,-INF,k-)-getsum(root1[l-],-INF,INF,-INF,k-); k=getkth(root2[l-],root2[r],-INF,INF,h);
res+=getsum(root2[r],-INF,INF,k,INF)-getsum(root2[l-],-INF,INF,k,INF);
res-=k*(r-mid+);
res+=(mid-l)*k;
res-=getsum(root2[r],-INF,INF,-INF,k-)-getsum(root2[l-],-INF,INF,-INF,k-); printf("%.2lf\n",0.5*res);
}
}