扫描线+区间更新

题解

/*
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. pycharm git无法使用问题(待解决)

    PyCharm 2017.3.1 (Community Edition)Build #PC-173.3942.36, built on December 14, 2017JRE: 1.8.0_152- ...

  2. 函数和常用模块【day06】:subprocess模块(十)

    本节内容 1.概述 2.前言 3.subprocess模块 4.subprocess.Popen() 一.概述 我们在实际的工作中,需要跟操作系统的命令做交互,但我们如何用python去跟操作系统之间 ...

  3. JavaSE学习总结(五)——封装,继承,多态很简单

    java面向对象的三大特性是:封装.继承与多态,是面向对象编程的核心. 一.封装 简单说封装就是将同一类事物的特性与功能包装在一起,对外暴露调用的接口. 封装:封装也称信息隐藏,是指利用抽象数据类型把 ...

  4. Quartz.net创建windows服务

    序言 安装服务 sc create XXService binpath= "XXService.exe" start= auto sc description XXService ...

  5. Dojo与jQuery综合比较分析

    最近一直都在参与项目,无法抽空写些或者看些东西,周末抽了点时间看了下关于Dojo和Jquery的东西,在CSDN上看到一篇两个框架进行对比的文章,感觉写的不错,就拿了过来,没有别的意思,一来想保留下来 ...

  6. 搭建Linux下Android程序开发环境

    从AndroidStudio中文社区下载SDK压缩包,http://dl.google.com/android/android-sdk_r24.2-linux.tgz. 解压到某个目录,比如我的~/p ...

  7. 2017CCPC秦皇岛 C题Crusaders Quest&&ZOJ3983【模拟+STL】

    链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3983 题意: 给定9个血槽,有三种物品,每次可以把连续相同的物品抵消 ...

  8. [CQOI2012]组装 (贪心)

    CQOI2012]组装 solution: 蒟蒻表示并不会模拟退火,所以用了差分数组加贪心吗.我们先来看题: 在数轴上的某个位置修建一个组装车间 到组装车间距离的平方的最小值. 1<=n< ...

  9. Maven聚合工程的使用

    创建一个service模块 接下来,在该项目中创建一个接口 创建一个实现类,并实现接口 在sm1234-web项目中,调用service的方法,需要在该项目的pom.xml中引入依赖Service模块 ...

  10. 2018-2019-2 网络对抗技术 20165320 Exp4 恶意代码分析

    2018-2019-2 网络对抗技术 20165320 Exp4 恶意代码分析 一.实践目标 监控你自己系统的运行状态,看有没有可疑的程序在运行 分析一个恶意软件,就分析Exp2或Exp3中生成后门软 ...