思维题,对于曼哈顿距离,很多时候都是把绝对值拆开,我们发现,对于两个点一定是一正一负取大的,我们发现这就是对立的两种情况
进一步发现k只有5个,很容易联想到状压,因此我们对于最大的曼哈顿距离就是两个状态的和,他们的各个位仅有一个1并且总和有k个1
接下来我们只需要维护一个区间最大值,这可以使用线段树维护
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e5+10; const int inf=0x3f3f3f3f; int n,k; struct ele{ int f[40]; }; struct node{ int l,r; ele val; }tr[N<<2]; int a[N][10]; void pushup(int u){ for(int i=0;i<(1<<k);i++){ tr[u].val.f[i]=max(tr[u<<1].val.f[i],tr[u<<1|1].val.f[i]); } } void build(int u,int l,int r){ if(l==r){ tr[u]={l,r}; for(int i=0;i<(1<<k);i++){ tr[u].val.f[i]=0; for(int j=0;j<k;j++){ if(i>>j&1){ tr[u].val.f[i]+=a[l][j]; } else{ tr[u].val.f[i]-=a[l][j]; } } } } else{ tr[u]={l,r}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } } void modify(int u,int x){ if(tr[u].l==tr[u].r){ for(int i=0;i<(1<<k);i++){ tr[u].val.f[i]=0; for(int j=0;j<k;j++){ if(i>>j&1){ tr[u].val.f[i]+=a[x][j]; } else{ tr[u].val.f[i]-=a[x][j]; } } } return ; } int mid=tr[u].l+tr[u].r>>1; if(x<=mid) modify(u<<1,x); else modify(u<<1|1,x); pushup(u); } ele merge(ele x,ele y){ ele c; for(int i=0;i<(1<<k);i++){ c.f[i]=max(x.f[i],y.f[i]); } return c; } ele query(int u,int l,int r){ if(tr[u].l>=l&&tr[u].r<=r){ return tr[u].val; } int mid=tr[u].l+tr[u].r>>1; if(l>mid) return query(u<<1|1,l,r); else if(r<=mid) return query(u<<1,l,r); else{ auto d1=query(u<<1,l,r); auto d2=query(u<<1|1,l,r); d1=merge(d1,d2); return d1; } } int main(){ ios::sync_with_stdio(false); cin>>n>>k; int i,j; for(i=1;i<=n;i++){ for(j=0;j<k;j++){ cin>>a[i][j]; } } build(1,1,n); int q; cin>>q; while(q--){ int opt; cin>>opt; if(opt==1){ int x; cin>>x; for(i=0;i<k;i++){ cin>>a[x][i]; } modify(1,x); } else{ int l,r; cin>>l>>r; auto tmp=query(1,l,r); int ans=0; for(i=0;i<(1<<k-1);i++){ ans=max(ans,tmp.f[i]+tmp.f[(1<<k)-i-1]); } cout<<ans<<endl; } } }