有一 k k k维点序列。
求 [ l , r ] [l,r] [l,r]之间 Manhattan \text{Manhattan} Manhattan距离最大的点。要求点修改区间查询。
解:每维的坐标分解如下:
∣ a j − b j ∣ = a j − b j o r b j − a j , j = 1 , 2 , . . . , k |a_{j}-b_j|=a_{j}-b_{j}\ or\ b_{j}-a_{j},j=1,2,...,k ∣aj−bj∣=aj−bj or bj−aj,j=1,2,...,k
因此一个点的 Manhattan \text{Manhattan} Manhattan被 2 k 2^k 2k种情况控制。
假设 M i ( a , b ) M_i(a,b) Mi(a,b)代表其中的第 i i i种情况, M ( a , b ) M(a,b) M(a,b)代表 a , b a,b a,b的 Manhattan \text{Manhattan} Manhattan距离。可以证明:
M ( a , b ) = max i = 1 2 k { M i ( a , b ) } M(a,b)=\max_{i=1}^{2^k}\{M_i(a,b)\} M(a,b)=i=1max2k{Mi(a,b)}
所以:
res = max a , b ∈ a [ l , r ] M ( a , b ) = max a , b ∈ a [ l , r ] max i = 1 2 k { M i ( a , b ) } = max i = 1 2 k max a , b ∈ a [ l , r ] { M i ( a , b ) } \text{res}=\max_{a,b\in a[l,r]} M(a,b)=\max_{a,b\in a[l,r]} \max_{i=1}^{2^k}\{M_i(a,b)\}= \max_{i=1}^{2^k}\max_{a,b\in a[l,r]}\{M_i(a,b)\} res=a,b∈a[l,r]maxM(a,b)=a,b∈a[l,r]maxi=1max2k{Mi(a,b)}=i=1max2ka,b∈a[l,r]max{Mi(a,b)}
显然 max a , b ∈ a [ l , r ] { M i ( a , b ) } \displaystyle \max_{a,b\in a[l,r]}\{M_i(a,b)\} a,b∈a[l,r]max{Mi(a,b)}可以通过线段树维护。因此总的时间复杂度为 O ( 2 k n lg n ) \mathrm{O}(2^kn\lg n) O(2knlgn)。
#include
#include
#include
#include
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char GET_CHAR(){
if(head==tail){
int l=fread(buffer,1,BufferSize,stdin);
tail=(head=buffer)+l;
if(head==tail)return EOF;
}
return *head++;
}
inline int READ(){
int x=0,f=1;char c=GET_CHAR();
for(;!isdigit(c);c=GET_CHAR()){
if(c==EOF)return EOF;
if(c=='-')f=-1;
}
for(;isdigit(c);c=GET_CHAR())x=(((x<<2)+x)<<1)+c-'0';
return x*f;
}
const int N=200005;
int sgs[N<<2][32],sgt[N<<2][32];
int a[N][6];int k,kk;
int rl[32],rr[32];
void build(int p,int l,int r){
if(l==r){
int res;
for(int i=0;i<kk;i++){
res=0;
for(int j=0;j<k;j++){
if((i>>j)&1){
res+=a[l][j];
}else{
res-=a[l][j];
}
}
sgs[p][i]=sgt[p][i]=res;
}
return ;
}
int m=(l+r)>>1;
build(p<<1,l,m);
build(p<<1|1,m+1,r);
for(int i=0;i<kk;i++){
sgs[p][i]=min(sgs[p<<1][i],sgs[p<<1|1][i]);
sgt[p][i]=max(sgt[p<<1][i],sgt[p<<1|1][i]);
}
}
void ck(int p,int l,int r){
if(l==r)return ;
int m=(l+r)>>1;
ck(p<<1,l,m);ck(p<<1|1,m+1,r);
}
void update(int p,int l,int r,int x){
if(l==r){
int res;
for(int i=0;i<kk;i++){
res=0;
for(int j=0;j<k;j++){
if((i>>j)&1){
res+=a[l][j];
}else{
res-=a[l][j];
}
}
sgs[p][i]=sgt[p][i]=res;
}
return ;
}
int m=(l+r)>>1;
if(x<=m)update(p<<1,l,m,x);
else update(p<<1|1,m+1,r,x);
for(int i=0;i<kk;i++){
sgs[p][i]=min(sgs[p<<1][i],sgs[p<<1|1][i]);
sgt[p][i]=max(sgt[p<<1][i],sgt[p<<1|1][i]);
}
}
void query(int p,int l,int r,int L,int R){
if(L<=l&&r<=R){
for(int i=0;i<kk;i++){
rl[i]=min(sgs[p][i],rl[i]);
rr[i]=max(sgt[p][i],rr[i]);
}
return ;
}
int m=(l+r)>>1;
if(L<=m)query(p<<1,l,m,L,R);
if(m< R)query(p<<1|1,m+1,r,L,R);
}
int main(){
int n;
n=READ();k=READ();
kk=1<<k;
for(int i=1;i<=n;i++){
for(int j=0;j<k;j++){
a[i][j]=READ();
}
}
build(1,1,n);
int q=0;
q=READ();
while(q--){
int o;
o=READ();
if(o==1){
int i;
i=READ();
for(int j=0;j<k;j++){
a[i][j]=READ();
}
update(1,1,n,i);
}else{
int l,r;
l=READ();r=READ();
for(int i=0;i<kk;i++)rl[i]=0x3f3f3f3f,rr[i]=-0x3f3f3f3f;
query(1,1,n,l,r);
int res=0;
for(int i=0;i<kk;i++){
res=max(res,rr[i]-rl[i]);
}
printf("%d\n",res);
}
//ck(1,1,n);
}
}