扫描线+区间更新

题解

/*
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[];
int mid(){return MID(lft,rht);}
void init(int a,int b){flag[]=a;flag[]=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*];
void down(int ind){
for(int i=;i<;i++){
tree[LL(ind)].flag[i]+=tree[ind].flag[i];
tree[RR(ind)].flag[i]+=tree[ind].flag[i];
tree[ind].flag[i]=;
}
}
void build(int lft,int rht,int ind){
tree[ind].lft=lft;tree[ind].rht=rht;
tree[ind].init(,);
if(lft==rht) tree[ind].init(st[lft],ol[lft]);
else {
int mid=tree[ind].mid();
build(lft,mid,LL(ind));
build(mid+,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[];
mx=tree[ind].flag[];
}
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=; int id1=,id2=;
for(int i=;i<n;i++){
p[i].get();
y[i]=p[i].y;
}
sort(y,y+n);
sort(p,p+n);//把点按从左往右顺序排好
H[y[]]=;
for(int i=;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]=;
seg.build(,m,);
while(id1<n){
id2=id1;
while(p[id1].x==p[id2].x){//这一步删掉被st线穿过的点
//不是最低的点
if(p[id2].y!=y[]) //ol线低于p[id2].y情况的st分数就少了一份
seg.update(H[y[]],H[p[id2].y]-,,,-);
//不是最高的点
if(p[id2].y!=y[m]) //ol线高于p[id2].y的时候
seg.update(H[p[id2].y]+,H[y[m]],,,-);
if(++id2>=n) break;
}
int mii=n,mxx=;
for(int i=id1;i<id2;i++){//依次在st线上的点建立ol线并进行查询,找到使st得分最低的那个点
int tmp1,tmp2;
seg.query(H[p[i].y],,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[])
seg.update(H[y[]],H[p[i].y]-,,,);
if(p[i].y!=y[m])
seg.update(H[p[i].y]+,H[y[m]],,,);
}
id1=id2;
}
sort(mx.begin(),mx.end());
mx.erase(unique(mx.begin(),mx.end()),mx.end());
printf("Stan: %d; Ollie:",mi);
for(int i=;i<mx.size();i++)
printf(" %d",mx[i]);
printf(";\n");
}
return ;
}

poj2464扫描线好题,回头再做的更多相关文章

  1. cf276E 两棵线段树分别维护dfs序和bfs序,好题回头再做

    搞了一晚上,错了,以后回头再来看 /* 对于每次更新,先处理其儿子方向,再处理其父亲方向 处理父亲方向时无法达到根,那么直接更新 如果能达到根,那么到兄弟链中去更新,使用bfs序 最后,查询结点v的结 ...

  2. poj2464扫描线好题,树状数组解法

    用树状数组解比线段树快了好多,难度也下降许多 分别用两个树状数组维护当前扫描线左侧和右侧的点,离散化y轴即可 #include<iostream> #include<cstring& ...

  3. uva12436 回头再做一次

    线段树维护等差数列,结点维护首项+公差即可 #include <cstdio> #include <cstring> #include <algorithm> us ...

  4. hdu4942线段树模拟rotate操作+中序遍历 回头再做

    很有意思的题目,详细题解看这里 https://blog.csdn.net/qian99/article/details/38536559 自己的代码不知道哪里出了点问题 /* rotate操作不会改 ...

  5. Go: LeetCode简单题,简单做(sort.Search)

    前言 正值端午佳节,LeetCode也很懂.这两天都是简单题,早点做完去包粽子. 故事从一道简单题说起 第一个错误的版本 简单题 你是产品经理,目前正在带领一个团队开发新的产品.不幸的是,你的产品的最 ...

  6. CozyRSS开发记录3-标题栏再加强

    CozyRSS开发记录3-标题栏再加强 1.更精炼的标题栏 接下来,我们把窗口的边框和默认的标题栏给去掉,让Cozy看起来更像一个平板应用. 在主窗口的属性里,修改下列两个属性: 效果一目了然: 2. ...

  7. el-popover 的显示或隐藏,要在拿到真实dom之后再做控制

    el-popover 的显示或隐藏,要在拿到真实dom之后再做控制

  8. 【java】【多线程】等待开启的多个线程都执行完成,再做事情,怎么实现

    今天在controller中写一个接口用来测试模拟多个请求同时到达 下订单的情况, 怎么能有效保证高并发下的库存和销量的一致性呢?[具体实现方法:https://www.cnblogs.com/sxd ...

  9. Spark在处理数据的时候,会将数据都加载到内存再做处理吗?

    对于Spark的初学者,往往会有一个疑问:Spark(如SparkRDD.SparkSQL)在处理数据的时候,会将数据都加载到内存再做处理吗? 很显然,答案是否定的! 对该问题产生疑问的根源还是对Sp ...

随机推荐

  1. SQL记录-Oracle重命名表名例子

    rename table_1 to table_2

  2. POJ 2127 Greatest Common Increasing Subsequence

    You are given two sequences of integer numbers. Write a program to determine their common increasing ...

  3. bzoj千题计划301:bzoj4259: 残缺的字符串

    https://www.lydsy.com/JudgeOnline/problem.php?id=4259 令通配符=0 f[i+m-1]=Σ (a[i+j]-b[m-1-j])^2 * a[i+j] ...

  4. 转--python 基础

    核心库 1.NumPy 当我们用python来处理科学计算任务时,不可避免的要用到来自SciPy  Stack的帮助.SciPy Stack是一个专为python中科学计算而设计的软件包,注意不要将它 ...

  5. JavaScript数组倒序函数reverse()

    左边为原数组,右边为array.reverse()的结果: 函数很简单,但是 var temp = ChartConfig.getMonthData(); $scope.monthList = tem ...

  6. 词典的实现(3)--使用JAVA类库ArrayList实现Map数据结构

    1,在词典的实现(2)-借助顺序表(数组)实现词典文章中使用了自定义的数组代替ArrayList,并实现了Map数据结构的基本功能.而借助JAVA类库ArrayList类的一些方法可以更加容易地实现M ...

  7. u-boot移植(七)---代码修改---存储控制器

    一.CPU访问芯片的条件 CPU通过访问存储控制器,来读取外部设备的数据. CPU想访问一个芯片,需要如下条件(配置信息): 地址线 数据线:8位/16位/32位数据宽度 时钟/频率 其他芯片相关的特 ...

  8. Linux 重启网卡失败 Job for network.service failed because the control process exited with error code. See "systemctl status network.service" and "journalctl -xe" for details.

    linux下重启网卡使用命令 : service network restart 时报错: [root@slave01 hadoop]# service network restart Startin ...

  9. 转载-YARN的内存和CPU配置

    Hadoop YARN同时支持内存和CPU两种资源的调度,本文介绍如何配置YARN对内存和CPU的使用. YARN作为一个资源调度器,应该考虑到集群里面每一台机子的计算资源,然后根据applicati ...

  10. Mybatis进阶学习笔记——输出映射

    输出映射(例如一个方法的返回至使用什么类型去接收) 1.基本类型 <!-- 统计记录数 --> <select id="queryTotalCount" resu ...