1941: [Sdoi2010]Hide and Seek|动态加点线段树

传统的K-Dtree姿势http://blog.csdn.net/ws_yzy/article/details/50855522
对计算曼哈顿距离分四种情况讨论,枚举每一个点,维护它的左下,左上,右下,右上的点,在相同区域的点的计算曼哈顿距离的符号是相同的
先用左下方的点更新每一个点,对于点 (x,y) ,此时线段树中存的是 xy ,维护最大值和最小值
从左到右枚举每一个点 (x,y) ,询问线段树中区间 [0,y] 中的最大值和最小值来更新到这个点的距离的最值,然后在将该点插入到线段树中
其他区域也同理

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#define N 4000022
#define M 500050
using namespace std;
int sc()
{
    int i=0,f=1; char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
    return i*f;
}
struct W{int x,y;}a[M];
int mn[N],mx[N],ll[N],lr[N],cnt;
int ans1[M],ans2[M];
int n,MX,root,ans=1e9;
bool cmp(W a,W b)
{
    return a.x<b.x;
}
void push_up(int x)
{
    mn[x]=min(mn[ll[x]],mn[lr[x]]);
    mx[x]=max(mx[ll[x]],mx[lr[x]]);
}
void insert(int &x,int l,int r,int p,int v)
{
    if(l==r)
    {
        if(x)
            mn[x]=min(mn[x],v),
            mx[x]=max(mx[x],v);
        else x=++cnt,mn[x]=mx[x]=v;
        return;
    }
    if(!x)x=++cnt;
    int mid=l+r>>1;
    if(p<=mid)insert(ll[x],l,mid,p,v);
    else insert(lr[x],mid+1,r,p,v);
    push_up(x);
}
int query_mx(int x,int L,int R,int l,int r)
{
    if(!x)return -1e9;
    if(L==l&&R==r)return mx[x];
    int mid=L+R>>1;
    if(r<=mid)return query_mx(ll[x],L,mid,l,r);
    else if(l>mid)return query_mx(lr[x],mid+1,R,l,r);
    else return max(query_mx(ll[x],L,mid,l,mid),query_mx(lr[x],mid+1,R,mid+1,r));
}
int query_mn(int x,int L,int R,int l,int r)
{
    if(!x)return 1e9;
    if(L==l&&R==r)return mn[x];
    int mid=L+R>>1;
    if(r<=mid)return query_mn(ll[x],L,mid,l,r);
    else if(l>mid)return query_mn(lr[x],mid+1,R,l,r);
    else return min(query_mn(ll[x],L,mid,l,mid),query_mn(lr[x],mid+1,R,mid+1,r));
}
int main()
{
    mn[0]=1e9,mx[0]=-1e9;
    n=sc();
    for(int i=1;i<=n;i++)
        ans1[i]=-1e9,ans2[i]=1e9,
        a[i].x=sc(),a[i].y=sc(),
        MX=max(MX,max(a[i].x,a[i].y));
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        ans1[i]=max(ans1[i],a[i].x+a[i].y+query_mx(root,0,MX,0,a[i].y));
        ans2[i]=min(ans2[i],a[i].x+a[i].y+query_mn(root,0,MX,0,a[i].y));
        insert(root,0,MX,a[i].y,-a[i].x-a[i].y);
    }
    for(int i=1;i<=cnt;i++)
        ll[i]=lr[i]=0;
    root=cnt=0;
    for(int i=1;i<=n;i++)
    {
        ans1[i]=max(ans1[i],a[i].x-a[i].y+query_mx(root,0,MX,a[i].y,MX));
        ans2[i]=min(ans2[i],a[i].x-a[i].y+query_mn(root,0,MX,a[i].y,MX));
        insert(root,0,MX,a[i].y,-a[i].x+a[i].y);
    }
    for(int i=1;i<=cnt;i++)
        ll[i]=lr[i]=0;
    root=cnt=0;
    for(int i=n;i>=1;i--)
    {
        ans1[i]=max(ans1[i],-a[i].x+a[i].y+query_mx(root,0,MX,0,a[i].y));
        ans2[i]=min(ans2[i],-a[i].x+a[i].y+query_mn(root,0,MX,0,a[i].y));
        insert(root,0,MX,a[i].y,a[i].x-a[i].y);
    }
    for(int i=1;i<=cnt;i++)
        ll[i]=lr[i]=0;
    root=cnt=0;
    for(int i=n;i>=1;i--)
    {
        ans1[i]=max(ans1[i],-a[i].x-a[i].y+query_mx(root,0,MX,a[i].y,MX));
        ans2[i]=min(ans2[i],-a[i].x-a[i].y+query_mn(root,0,MX,a[i].y,MX));
        insert(root,0,MX,a[i].y,a[i].x+a[i].y);
    }
    for(int i=1;i<=n;i++)
        ans=min(ans,ans1[i]-ans2[i]);
    cout<<ans;
    return 0;
}

你可能感兴趣的:(线段树)