BZOJ5462 APIO2018新家(线段树+堆)
一个显然的做法是二分答案后转化为查询区间颜色数,可持久化线段树记录每个位置上一个同色位置,离线后set+树状数组套线段树维护。这样是三个log的。
注意到我们要知道的其实只是是否所有颜色都在该区间出现,可以改为查询后缀区间的上一个同色位置中最小的。这样我们就只需要set+线段树就可以维护了,同样二分答案是两个log。直接在线段树上二分就变成了一个log。
给每种颜色在坐标-inf和inf处加点来避免乱七八糟的讨论。离散化一下。对于相同坐标的点,在叶子维护堆即可。调过样例就能1A了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
using namespace std;
#define ll long long
#define N 600010
#define inf 600000003
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,m,q,t,L[N<<],R[N<<],tree[N<<],ans[N],u[N];
struct data
{
int x,t,op;int p,i;
bool operator <(const data&a) const
{
return t<a.t||t==a.t&&abs(op)>abs(a.op);
}
}a[N<<];
priority_queue<int,vector<int>,greater<int> > ins[N<<],del[N<<];
multiset<int> color[N];
void build(int k,int l,int r)
{
L[k]=l,R[k]=r;tree[k]=inf;
if (l==r) return;
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
}
int query(int k,int l,int r,int x,int last)
{
if (L[k]==R[k]) return max(u[L[k]]-x,x-last);
int mid=L[k]+R[k]>>;
if (r<=mid) return query(k<<,l,r,x,min(tree[k<<|],last));
else if (l>mid) return query(k<<|,l,r,x,last);
else
{
if (u[mid]-x>x-min(last,tree[k<<|])) return query(k<<,l,mid,x,min(last,tree[k<<|]));
else return min(x-min(last,tree[k<<|]),query(k<<|,mid+,r,x,last));
}
}
void modify(int k,int p,int x,int op)
{
if (L[k]==R[k])
{
if (op==) ins[k].push(x);else del[k].push(x);
while (!del[k].empty()&&ins[k].top()==del[k].top()) ins[k].pop(),del[k].pop();
tree[k]=ins[k].empty()?inf:ins[k].top();
return;
}
int mid=L[k]+R[k]>>;
if (p<=mid) modify(k<<,p,x,op);
else modify(k<<|,p,x,op);
tree[k]=min(tree[k<<],tree[k<<|]);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj5462.in","r",stdin);
freopen("bzoj5462.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read(),q=read();
for (int i=;i<=n;i++)
{
int x=read(),y=read(),l=read(),r=read();
t++;a[t].x=x,a[t].t=l,a[t].op=,a[t].p=y;
t++;a[t].x=x,a[t].t=r+,a[t].op=-,a[t].p=y;
u[i]=x;
}
for (int i=;i<=q;i++) t++,a[t].x=read(),a[t].t=read(),a[t].op=,a[t].p=,a[t].i=i,u[n+i]=a[t].x;
sort(u+,u+n+q+);int v=unique(u+,u+n+q+)-u-;u[]=-inf,u[++v]=inf;
for (int i=;i<=t;i++) a[i].x=lower_bound(u,u+v+,a[i].x)-u;
build(,,v);
sort(a+,a+t+);
//for (int i=1;i<=t;i++) cout<<a[i].x<<' '<<a[i].t<<' '<<a[i].op<<' '<<a[i].p<<' '<<a[i].i<<endl;
for (int i=;i<=m;i++)
{
color[i].insert(),color[i].insert(v);
modify(,v,-inf,);
}
for (int i=;i<=t;i++)
if (a[i].op==) ans[a[i].i]=query(,a[i].x,v,u[a[i].x],inf);
else if (a[i].op==-)
{
multiset<int>::iterator it=color[a[i].p].find(a[i].x);
it++;int x=*it;
it--,it--;int y=*it;
it++;color[a[i].p].erase(it);
modify(,x,u[a[i].x],-),modify(,a[i].x,u[y],-),modify(,x,u[y],);
}
else
{
multiset<int>::iterator it=color[a[i].p].lower_bound(a[i].x);
int x=*it;
it--;int y=*it;
color[a[i].p].insert(a[i].x);
modify(,x,u[a[i].x],),modify(,a[i].x,u[y],),modify(,x,u[y],-);
}
for (int i=;i<=q;i++) printf("%d\n",ans[i]>inf/?-:ans[i]);
return ;
}
BZOJ5462 APIO2018新家(线段树+堆)的更多相关文章
- [BZOJ5462][APIO2018]新家(线段树+堆)
其实这个题第一反应一定是线段树分治,但是这样反而更难考虑了(实际上是可做的但很难想到),可见即使看上去最贴切的算法也未必能有效果. 考虑这个DS题,没有什么模型的转化,可能用到的无非就是线段树.平衡树 ...
- LOJ 2585 「APIO2018」新家 ——线段树分治+二分答案
题目:https://loj.ac/problem/2585 算答案的时候要二分! 这样的话,就是对于询问位置 x ,二分出一个最小的 mid 使得 [ x-mid , x+mid ] 里包含所有种类 ...
- [APIO2018] New Home 新家 [线段树,multiset]
线段树的每个点表示当前点的前驱,即这个颜色上一次出现的位置,这个玩意multiset随便写写就完了. 重要的是怎么查询答案,无解显然先判掉. 线段树上二分就可以了 #include <bits/ ...
- luogu P4632 [APIO2018] New Home 新家 线段树 set 二分
写了一种比较容易理解 但是常数很大的sol. 容易发现可以扫描线. 维护好序列之后发现很难查距离 考虑二分. 这里二分可以在线段树上进行 当然可能存在一些问题 如果离散化的话需要处理一些比较麻烦的细节 ...
- [JLOI2014]松鼠的新家(线段树,树链剖分)
题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...
- 「APIO2018新家」
「APIO2018新家」 题目描述 五福街是一条笔直的道路,这条道路可以看成一个数轴,街上每个建筑物的坐标都可以用一个整数来表示.小明是一位时光旅行者,他知道在这条街上,在过去现在和未来共有 \(n\ ...
- LOJ.2585.[APIO2018]新家(二分 线段树 堆)
LOJ 洛谷 UOJ BZOJ 四OJ Rank1 hhhha 表示这个b我能装一年→_→ 首先考虑离线,将询问按时间排序.对于每个在\([l,r]\)出现的颜色,拆成在\(l\)加入和\(r+1\) ...
- 2015 UESTC 数据结构专题E题 秋实大哥与家 线段树扫描线求矩形面积交
E - 秋实大哥与家 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/contest/show/59 De ...
- 【BZOJ4504】K个串 可持久化线段树+堆
[BZOJ4504]K个串 Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计 ...
随机推荐
- day47
高级布局 一.文档流(normal flow) 1.概念 本质为normal flow(普通流.常规流)将窗体自上而下分成一行一行,块级元素从上至下.行内元素在每行中从左至右的顺序依次排放元素. v_ ...
- 感言&2
我写下这些,不是为了向谁诉说我的苦难,我家庭的苦难,而只是想说,朋友,当你们能够坐在星巴克里点杯咖啡打开Macbook刷知乎,思考“人为什么努力”这样的问题时有无数个像我一样出身的孩子在拼命,不因为什 ...
- 20155209 林虹宇 Exp 8 Web基础
Exp 8 Web基础 Web前端HTML 正常安装.启停Apache kali本机自带apache,上个实验已经使用过,直接使用 查看80端口. 127.0.0.1 编写一个含有表单的html 在浏 ...
- 20155334 网络对抗PC平台逆向破解(二)
注入Shellcode并运行攻击 shellcode就是一段机器指令(code) 通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe) ...
- python变量名感悟
我感悟的是python的变量名其实就可以理解为C/C++中的指针! 1.python的变量在使用之前必须赋值,就像指针在使用之前不能为空. 2.python的内存可以用del释放,C++可以用dele ...
- CS229笔记:分类与逻辑回归
逻辑回归 对于一个二分类(binary classification)问题,\(y \in \left\{0, 1\right\}\),如果直接用线性回归去预测,结果显然是非常不准确的,所以我们采用一 ...
- ubuntu下安装搜狗输入法
1.如果系统中未安装依赖fcitx,libssh2-1,或者依赖fcitx,libssh2-1的版本低的话,则需提前安装或者升级,否则安装输入法时会出错 安装命令 sudo apt-get insta ...
- libgdx学习记录9——FreeType,ttf中文显示
前面讲到使用Hireo创建的BitmapFont以显示中文字体.这种方式效率很高,当所要显示的字的总数较少,并且大小比较固定时,可以采用这种方式. 但是这种也有弊端: (1)字体大小不能随意设置,当放 ...
- linux下ipython无法保存历史记录
在Centos7下使用ipython时,发现有个warning,提示无法保存历史记录 [root@localhost pip-]# ipython /usr/local/lib/python3./si ...
- stl源码剖析 详细学习笔记 算法(3)
//---------------------------15/03/30---------------------------- //min_element template<class Fo ...