poj2464扫描线好题,回头再做

扫描线+区间更新

题解

/*
st[i],ol[i]表示y坐标大于y[i]和小于y[i]的点
两颗线段树建立在y轴上,区间[l,r]ol线选在[l,r]时st的分数
每次查询完成后再更新一次
遍历每条st线上的ol线,这是单点查询
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
#define N 200005
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define MID(a,b) (a+((b-a)>>1))

struct Point{
    int x,y;
    void get(){scanf("%d%d",&x,&y);}
    bool operator<(const Point & b)const
    { return x<b.x; }
} p[N];
struct node{//线段树结点
    int lft,rht;
    int flag[2];
    int mid(){return MID(lft,rht);}
    void init(int a,int b){flag[0]=a;flag[1]=b;}
};
int n,m,mi;
vector<int> mx;
map<int,int> H;
int y[N],st[N],ol[N];//离散化数轴,大于等于y[i]的点数,小于等于y[i]的点
struct Segtree{
    node tree[N*4];
    void down(int ind){
        for(int i=0;i<2;i++){
            tree[LL(ind)].flag[i]+=tree[ind].flag[i];
            tree[RR(ind)].flag[i]+=tree[ind].flag[i];
            tree[ind].flag[i]=0;
        }
    }
    void build(int lft,int rht,int ind){
        tree[ind].lft=lft;tree[ind].rht=rht;
        tree[ind].init(0,0);
        if(lft==rht) tree[ind].init(st[lft],ol[lft]);
        else {
            int mid=tree[ind].mid();
            build(lft,mid,LL(ind));
            build(mid+1,rht,RR(ind));
        }
    }
    void update(int st,int ed,int ind,int type,int valu){
        int lft=tree[ind].lft,rht=tree[ind].rht;
        if(st<=lft && ed>=rht) 
            tree[ind].flag[type]+=valu;
        else {
            down(ind);
            int mid=tree[ind].mid();
            if(st<=mid) update(st,ed,LL(ind),type,valu);
            if(ed>mid) update(st,ed,LL(ind),type,valu);
        }
    }
    void query(int pos,int ind,int &mi,int &mx){
        if(tree[ind].lft==tree[ind].rht){
            mi=tree[ind].flag[0];
            mx=tree[ind].flag[1];
        }
        else {
            down(ind);
            int mid=tree[ind].mid();
            if(pos<=mid) return query(pos,LL(ind),mi,mx);
            if(pos>mid) return query(pos,RR(ind),mi,mx);
        }
    }
}seg;
int main(){
    while(scanf("%d",&n),n){
        H.clear();mx.clear();mi=m=0;

        int id1=0,id2=0;
        for(int i=0;i<n;i++){
            p[i].get();
            y[i]=p[i].y;
        }
        sort(y,y+n);
        sort(p,p+n);//把点按从左往右顺序排好
        H[y[0]]=0;
        for(int i=0;i<n;i++)//遍历一次纵坐标
            if(y[m]!=y[i]){
                st[m]=n-i;//高于y[i]的点数
                y[++m]=y[i];
                ol[m]=i;//低于y[i]的点数
                H[y[m]]=m;
            }
        st[m]=0;
        seg.build(0,m,1);
        while(id1<n){
            id2=id1;
            while(p[id1].x==p[id2].x){//这一步删掉被st线穿过的点
                //不是最低的点
                if(p[id2].y!=y[0]) //ol线低于p[id2].y情况的st分数就少了一份
                    seg.update(H[y[0]],H[p[id2].y]-1,1,0,-1);
                //不是最高的点
                if(p[id2].y!=y[m]) //ol线高于p[id2].y的时候
                    seg.update(H[p[id2].y]+1,H[y[m]],1,1,-1);
                if(++id2>=n) break;
            }
            int mii=n,mxx=0;
            for(int i=id1;i<id2;i++){//依次在st线上的点建立ol线并进行查询,找到使st得分最低的那个点
                int tmp1,tmp2;
                seg.query(H[p[i].y],1,mii,mxx);
                mii=min(mii,tmp1);
                mxx=max(mxx,tmp2);
            }

            if(mii==mi) mx.push_back(mxx);//找到了ol的新解
            else if(mii>mi){//找到了st的更优解
                mi=mii;
                mx.clear();mx.push_back(mxx);
            }
            //再更新一次,把这条线上删掉的反向加回去:因为扫描线往后扫描这条线上原来应该属于ol的现在属于st,原来属于st的现在应该属于ol
            for(int i=id1;i<id2;i++){
                if(p[i].y!=y[0])
                    seg.update(H[y[0]],H[p[i].y]-1,1,1,1);
                if(p[i].y!=y[m])
                    seg.update(H[p[i].y]+1,H[y[m]],1,0,1);
            }
            id1=id2;
        }
        sort(mx.begin(),mx.end());
        mx.erase(unique(mx.begin(),mx.end()),mx.end());
        printf("Stan: %d; Ollie:",mi);
        for(int i=0;i<mx.size();i++)
            printf(" %d",mx[i]);
        printf(";\n");
    }
    return 0;
}

 

posted on 2018-11-14 16:03  zsben  阅读(212)  评论(0编辑  收藏  举报

导航