由于要求n个点的最大曼哈顿距离,并且要执行插入,删去操作,如果对距离公式什么都不做的话,会发现复杂度太高了,tle肯定。再来看一下二维式子,无非有四种方式:
(x1-x2)+(y1-y2),(-x1+x2)+(y1-y2),(x1-x2)+(y2-y1),(x2-x1)+(y2-y1).
毫无规律再变化一下。
(x1+y1)-(x2+y2),(-x1+y1)-(-x2+y2),(x1-y1)-(x2-y2).....
所以可以用线段树来维护一个点的相应的值。
二进制来表示x1,y1,z1,t1,k1的正负值。
//hdu 4666 线段树+最大曼哈顿距离 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; int que[60005],q[60005][6],ans[60005],op,wei; #define inf 0x3f3f3f3f struct ee { int ma,mi,l,r; }tree[4*60005]; void pushup(int c) { tree[c].ma=max(tree[c*2].ma,tree[c*2+1].ma); tree[c].mi=min(tree[c*2].mi,tree[c*2+1].mi); } void insert(int a,int s,int time) { if(tree[a].l==tree[a].r) { int i,cnt=0; for(i=0;i<wei;i++) { if((1<<i)&time) { cnt+=q[s][i+1]; } else { cnt-=q[s][i+1]; } } tree[a].ma=cnt;tree[a].mi=cnt; return; } int mid=(tree[a].l+tree[a].r)/2; if(s<=mid) insert(a*2,s,time); else insert(a*2+1,s,time); pushup(a); } void build(int a,int sta,int end) { tree[a].l=sta; tree[a].r=end; tree[a].ma=-inf; tree[a].mi=inf; if(sta==end) return; int mid=(sta+end)/2; build(a*2,sta,mid); build(a*2+1,mid+1,end); pushup(a); } void clear(int a,int s) { if(tree[a].l==tree[a].r) { tree[a].ma=-inf; tree[a].mi=inf; return; } int mid=(tree[a].l+tree[a].r)/2; if(s<=mid) clear(a*2,s); else clear(a*2+1,s); pushup(a); } void init() { memset(ans,0,sizeof(ans)); memset(q,0,sizeof(q)); int i; for(i=1;i<=op;i++) { scanf("%d",&que[i]); if(!que[i]) { for(int j=1;j<=wei;j++) { scanf("%d",&q[i][j]); } } else scanf("%d",&q[i][0]); } } int main () { //freopen("d:\\in.txt","r",stdin); while(scanf("%d%d",&op,&wei)==2) { init(); int ii; for(ii=0;ii<(1<<wei);ii++) //二进制枚举状态 { build(1,1,op); for(int i=1;i<=op;i++) { if(que[i]==1) { clear(1,q[i][0]); } else { insert(1,i,ii); } ans[i]=max(ans[i],tree[1].ma-tree[1].mi); } } for(int i=1;i<=op;i++) printf("%d\n",ans[i]); } return 0; }