由于要求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;
}