1. 程式人生 > 實用技巧 >CF1093G Multidimensional Queries(線段樹)

CF1093G Multidimensional Queries(線段樹)

思維題,對於曼哈頓距離,很多時候都是把絕對值拆開,我們發現,對於兩個點一定是一正一負取大的,我們發現這就是對立的兩種情況

進一步發現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; } } }
View Code