zoukankan      html  css  js  c++  java
  • 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(";
    ");
        }
        return 0;
    }
  • 相关阅读:
    #leetcode687.最长同值路径
    #leetcode404.所有左叶子节点之和
    #leetcode111.二叉树的最小深度
    #leetcode101.对称二叉树
    #leetcode437.路径总和II
    #leetcode112.路径总和
    #leetcode543.二叉树的直径
    #leetcode110.平衡二叉树
    springboot数据库密码加密-使用自定义加密算法
    PHP加密
  • 原文地址:https://www.cnblogs.com/zsben991126/p/9958441.html
Copyright © 2011-2022 走看看