題意
給出n(n<=2E5)個k(k<=5)維空間中的點,每次詢問[l,r]中兩個點曼哈頓距離的最大值(可以類比二維)
思考
根據初中數學,我們知道。
而每個維度上的曼哈頓距離是獨立的。
k又很小,因此我們可以一股腦地分類討論,把所有可能的結果算出來。
設f[S]表示k位二進位制下k個維度的正負情況,如k=3時,(2,3,3)對應S(2)=110的結果為2+2-3。
每次列舉S的所有情況,一股腦塞進去就行了!最後的結果就是max{f[i]+f[2^k-i-1]}。
為什麼是對的?因為這求的是最大值,所有可能的情況中電腦會機械化地算出最大可能的結果。
簡單線段樹維護。
程式碼
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=2E5+5; 4 int n,k,m,a[maxn][6]; 5 struct tree{int l,r,f[32];}t[maxn*4]; 6 tree merge(tree x,tree y) 7 { 8 tree z; 9 z.l=x.l,z.r=y.r; 10 for(int i=0;i<(1<<k);++i)z.f[i]=max(x.f[i],y.f[i]); 11 return z; 12 } 13 void get(int x,int num) 14 { 15 for(int i=0;i<(1<<k);++i) 16 { 17 int sum=0; 18 for(int j=0;j<k;++j) 19 { 20 if(i&(1<<j))sum+=a[x][j]; 21 else sum-=a[x][j]; 22 } 23 t[num].f[i]=sum; 24 } 25 } 26 void build(int l,int r,int num) 27 { 28 t[num].l=l;t[num].r=r; 29 if(l==r) 30 { 31 get(l,num); 32 return; 33 } 34 int mid=(l+r)>>1; 35 build(l,mid,num*2);build(mid+1,r,num*2+1); 36 t[num]=merge(t[num*2],t[num*2+1]); 37 } 38 void change(int pos,int num) 39 { 40 if(t[num].l==t[num].r) 41 { 42 get(pos,num); 43 return; 44 } 45 int mid=(t[num].l+t[num].r)>>1; 46 if(pos<=mid)change(pos,num*2); 47 else change(pos,num*2+1); 48 t[num]=merge(t[num*2],t[num*2+1]); 49 } 50 tree ask(int L,int R,int num) 51 { 52 if(L<=t[num].l&&t[num].r<=R)return t[num]; 53 int mid=(t[num].l+t[num].r)>>1; 54 if(R<=mid)return ask(L,R,num*2); 55 else if(mid<L)return ask(L,R,num*2+1); 56 else return merge(ask(L,R,num*2),ask(L,R,num*2+1)); 57 } 58 int main() 59 { 60 ios::sync_with_stdio(false); 61 cin>>n>>k; 62 for(int i=1;i<=n;++i) 63 for(int j=0;j<k;++j)cin>>a[i][j]; 64 cin>>m; 65 build(1,n,1); 66 while(m--) 67 { 68 int opt,x; 69 cin>>opt; 70 if(opt==1) 71 { 72 cin>>x; 73 for(int j=0;j<k;++j)cin>>a[x][j]; 74 change(x,1); 75 } 76 else 77 { 78 int l,r,ans=0; 79 cin>>l>>r; 80 tree u=ask(l,r,1); 81 for(int i=0;i<(1<<k);++i)ans=max(ans,u.f[i]+u.f[(1<<k)-i-1]); 82 cout<<ans<<endl; 83 } 84 } 85 return 0; 86 }