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的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计 ...
随机推荐
- GitHub上最火的40个Android开源项目(二)
21.drag-sort-listview DragSortListView(DSLV)是Android ListView的一个扩展,支持拖拽排序和左右滑动删除功能.重写了TouchIntercept ...
- python高速排序
import random def rand(n): for i in range(n): yield random.randint(0,1000) #创建一个随机数列表 def createList ...
- 利尔达推出工控解决方式 串口转以太网模块LSD1ES-W5500_S2E0
利尔达最近推出工控解决方式,串口转以太网模块LSD1ES-W5500_S2E0,模块基于WIZnet-W5500. 同一时候,这也是利尔达科技集团成为WIZnet代理商后,自行推出的第一款基于WIZn ...
- C/C++函数调用方式
__cdecl __fastcall与__stdcall,三者都是调用约定(Calling convention),它决定以下内容:1)函数参数的压栈顺序,2)由调用者还是被调用者把参数弹出栈,3)以 ...
- WPF Style
<Application x:Class="WzlyTool.App" xmlns="http://schemas.microsoft.com/winfx/20 ...
- 20155323刘威良《网络对抗》Exp3 免杀原理与实践
20155323刘威良<网络对抗>Exp3 免杀原理与实践 实践内容 1 正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,自己利用shellco ...
- linux下通过软连接实现访问项目路径外面的资源
在javaweb项目开发中,图片上传是个比较常见的场景.一般都是在项目路径下建个文件夹,然后上传到该文件夹下:这样这个图片就可以和静态资源一样被直接访问.这样的好处就是访问这图片特别方 ...
- 【调试】Core Dump是什么?Linux下如何正确永久开启?
[调试]Core Dump是什么?Linux下如何正确永久开启?
- ZAB协议和Paxos算法
前言在上一篇文章Paxos算法浅析中主要介绍了Paxos一致性算法应用的场景,以及对协议本身的介绍:Google Chubby是一个分布式锁服务,其底层一致性实现就是以Paxos算法为基础的:但这篇文 ...
- Python 学习 第三篇:数组类型(列表、字典和元组)
列表和字段都可以在原处进行修改,可以按照需求增长或缩短,并且可以包含任何类型的对象或被嵌套.列表和字典存储的是对象的引用,而不是拷贝. 一,列表 列表是有序的序列,每一个列表项的顺序是固定的,这使得列 ...