搜索的线段树优化

题目:

在地图上有n个堡垒,求相隔最近的两个堡垒的曼哈顿距离|x1-x2|+|y1-y2|

分析:如果暴力搜索那么复杂度将会极差,所以出现了排序后向前后搜索50个的闹剧啊啊;

遇到类似题目实际上可以利用表达式的化简利用数据结构优化复杂度

向将y排序,对于当前结点只统计当y值大于此点时对于答案的贡献

当前点x1,y1,也就是说:x2<x1||x1<x2 但是 y1<y2始终不变

那么将x由大到小排序,将y值对应为线段树下标,某一个值放入线段树维护以log时间内寻找最小值

|x2-x1|+|y2-y1|=x2-x1+y2-y1=(x2+y2)-(x1+y1),在线段树内放入x+y,每次遍历后再把当前节点动态放入线段树内

再将x由小到大排序,

|x2-x1|+|y2-y1|=x1-x2+y2-y1=(x1-y1)-(x2-y2),统计答案即可

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std;

const int N=100050;
const int inf=0x3f3f3f3f;
int n,my;

struct node{int x,y;}po[N];
bool cmp1(node a,node b){return a.x>b.x;}
bool cmp2(node a,node b){return a.x<b.x;} 
int mx[N<<2];
namespace segmentree{
    
    inline void pushup(int k){
        mx[k]=min(mx[k<<1],mx[k<<1|1]);}
    
    inline void build(int k,int l,int r){
        mx[k]=inf;
        if(l==r) return;
        int mid=(l+r)>>1;
        build(k<<1,l,mid);build(k<<1|1,mid+1,r);}
    
    inline int query(int k,int l,int r,int x,int y){
        if(x<=l&&r<=y) return mx[k];
        int mid=(l+r)>>1,res=inf;
        if(x<=mid) res=min(res,query(k<<1,l,mid,x,y));
        if(mid<y) res=min(res,query(k<<1|1,mid+1,r,x,y));
        return res;}
    
    inline void change(int k,int l,int r,int p,int d){
        if(l==r) {mx[k]=d;return;}
        int mid=(l+r)>>1;
        if(p<=mid) change(k<<1,l,mid,p,d);
        else change(k<<1|1,mid+1,r,p,d);
        pushup(k);}
}
using namespace segmentree;
int main(){
    freopen("away.in","r",stdin);
    freopen("away.out","w",stdout);
    scanf("%d",&n);my=0;
    for(int i=1;i<=n;i++){
       cin>>po[i].x>>po[i].y;
       my=max(my,po[i].y);}
    
    int ans=inf;
    build(1,1,my);
    sort(po+1,po+1+n,cmp1);
    for(int i=1;i<=n;i++){
        int dis=po[i].x+po[i].y;
        ans=min(ans,query(1,1,my,po[i].y,my)-dis);
        change(1,1,my,po[i].y,dis);}
    
    build(1,1,my);
    sort(po+1,po+1+n,cmp2);
    for(int i=1;i<=n;i++){
        int dis=po[i].y-po[i].x;
        ans=min(ans,query(1,1,my,po[i].y,my)-dis);
        change(1,1,my,po[i].y,dis);}
    printf("%d\n",ans);return 0;
}

或者将x翻入负值,也按由大到小排序也可

posted @ 2018-09-17 11:57  ASDIC减除  阅读(322)  评论(0编辑  收藏  举报