其实这个题第一反应一定是线段树分治,但是这样反而更难考虑了(实际上是可做的但很难想到),可见即使看上去最贴切的算法也未必能有效果。

考虑这个DS题,没有什么模型的转化,可能用到的无非就是线段树、平衡树和堆。

首先,显然地,将每个商店拆成出现和消失两个事件,然后按时间一次处理。接下来很容易想到二分,于是每次询问的就是[x-mid,x+mid]中是否包含了所有种类的商店。

考虑如何快速回答询问,我们在+inf处先插入所有种类的商店,并记录每个商店的同种类型的前驱(就是上一个同类型的商店在哪里)。

注意到,如果某种商店在[x-mid,x+mid]中没有出现,则必然有(x+mid,+inf)中的所有这种商店的前驱必然都小于x-mid。

问题再次转化为,实时更新每个商店的前驱,以及询问一个后缀最小值。

第一个操作,我们对每种商店都开一个set即可。第二个操作则是线段树基本操作,可能同坐标上有多个值,这个用可删除堆支持即可。

这样复杂度是两个log的,但往往线段树和二分可以合并。如果找到最大的i满足[i,+inf)的最小前驱mn,则mn+i<=2*x。

https://loj.ac/article/523

线段树上二分,于是复杂度就可以做到一个log了。

 #include<set>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define lson ls[x],L,mid
#define rson rs[x],mid+1,R
#define Root rt,0,inf
#define rep(i,l,r) for (int i=(l),_=(r); i<=_; i++)
using namespace std; const int M=,N=M*,inf=0x3f3f3f3f;
multiset<int>S[M];
int n,k,q,m,x,y,l,t,a,b,cnt,tot,id,rt,ans[M],pos[N],ls[N],rs[N],Mn[N];
struct P{ int op,x,t,k; bool operator <(const P &b)const{ return t!=b.t ? t<b.t : op>b.op; } }w[M*];
struct H{
priority_queue<int,vector<int>,greater<int> >Q1,Q2;
int size(){ return Q1.size()-Q2.size(); }
void push(int x){ Q1.push(x); }
void erase(int x){ Q2.push(x); }
int top(){ while (Q2.size() && Q1.top()==Q2.top()) Q1.pop(),Q2.pop(); return Q1.top(); }
}Q[M]; void mdf(int &x,int L,int R,int p,int u,int v){
if (!x) x=++tot;
if (L==R){
if (!pos[x]) pos[x]=++id;
H &q=Q[pos[x]];
if (~u) q.push(u);
if (~v) q.erase(v);
Mn[x]=q.size() ? q.top() : inf;
return;
}
int mid=(L+R)>>;
if (p<=mid) mdf(lson,p,u,v); else mdf(rson,p,u,v);
Mn[x]=min(Mn[ls[x]],Mn[rs[x]]);
} int que(int p){
int L=,R=inf,x=rt,ans=inf;
while (L!=R){
int mid=(L+R)>>,tmp=min(ans,Mn[rs[x]]);
if (p<=mid && tmp+mid>=*p) ans=tmp,R=mid,x=ls[x];
else L=mid+,x=rs[x];
}
return L-p;
} int main(){
freopen("apioa.in","r",stdin);
freopen("apioa.out","w",stdout);
scanf("%d%d%d",&n,&k,&q); Mn[]=inf;
rep(i,,k) S[i].insert(-inf),S[i].insert(inf),mdf(Root,inf,-inf,-);
rep(i,,n) scanf("%d%d%d%d",&x,&t,&a,&b),w[++m]=(P){,x,a,t},w[++m]=(P){-,x,b,t};
rep(i,,q) scanf("%d%d",&l,&y),w[++m]=(P){,l,y,i};
sort(w+,w+m+);
rep(i,,m){
P p=w[i];
if (p.op==){
multiset<int> &s=S[p.k];
multiset<int>::iterator q=s.upper_bound(p.x),r=q--;
mdf(Root,*r,p.x,*q); mdf(Root,p.x,*q,-);
if (s.size()==) cnt++; s.insert(p.x);
}
if (p.op==-){
multiset<int> &s=S[p.k];
s.erase(s.find(p.x));
if (s.size()==) cnt--;
multiset<int>::iterator q=s.upper_bound(p.x),r=q--;
mdf(Root,*r,*q,p.x); mdf(Root,p.x,-,*q);
}
if (p.op==) ans[p.k]=(cnt==k) ? que(p.x) : -;
}
rep(i,,q) printf("%d\n",ans[i]);
return ;
}

[BZOJ5462][APIO2018]新家(线段树+堆)的更多相关文章

  1. BZOJ5462 APIO2018新家(线段树+堆)

    一个显然的做法是二分答案后转化为查询区间颜色数,可持久化线段树记录每个位置上一个同色位置,离线后set+树状数组套线段树维护.这样是三个log的. 注意到我们要知道的其实只是是否所有颜色都在该区间出现 ...

  2. LOJ 2585 「APIO2018」新家 ——线段树分治+二分答案

    题目:https://loj.ac/problem/2585 算答案的时候要二分! 这样的话,就是对于询问位置 x ,二分出一个最小的 mid 使得 [ x-mid , x+mid ] 里包含所有种类 ...

  3. [APIO2018] New Home 新家 [线段树,multiset]

    线段树的每个点表示当前点的前驱,即这个颜色上一次出现的位置,这个玩意multiset随便写写就完了. 重要的是怎么查询答案,无解显然先判掉. 线段树上二分就可以了 #include <bits/ ...

  4. luogu P4632 [APIO2018] New Home 新家 线段树 set 二分

    写了一种比较容易理解 但是常数很大的sol. 容易发现可以扫描线. 维护好序列之后发现很难查距离 考虑二分. 这里二分可以在线段树上进行 当然可能存在一些问题 如果离散化的话需要处理一些比较麻烦的细节 ...

  5. [JLOI2014]松鼠的新家(线段树,树链剖分)

    题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...

  6. 「APIO2018新家」

    「APIO2018新家」 题目描述 五福街是一条笔直的道路,这条道路可以看成一个数轴,街上每个建筑物的坐标都可以用一个整数来表示.小明是一位时光旅行者,他知道在这条街上,在过去现在和未来共有 \(n\ ...

  7. LOJ.2585.[APIO2018]新家(二分 线段树 堆)

    LOJ 洛谷 UOJ BZOJ 四OJ Rank1 hhhha 表示这个b我能装一年→_→ 首先考虑离线,将询问按时间排序.对于每个在\([l,r]\)出现的颜色,拆成在\(l\)加入和\(r+1\) ...

  8. 2015 UESTC 数据结构专题E题 秋实大哥与家 线段树扫描线求矩形面积交

    E - 秋实大哥与家 Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/contest/show/59 De ...

  9. 【BZOJ4504】K个串 可持久化线段树+堆

    [BZOJ4504]K个串 Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计 ...

随机推荐

  1. 怎么替换jar包里面的文件?

    很多时候,我们需要替换包含在jar包里面的文件,例如修改里面的配置文件. 由于jar包已经生成,在不想重新用eclipse导出的情况下,我们怎么修改jar包里面的文件呢? 其实说出来很简单,可以使用以 ...

  2. Windows Socket 编程_ 简单的服务器/客户端程序

    转载自:http://blog.csdn.net/neicole/article/details/7459021 一.程序运行效果图 二.程序源代码 三.程序设计相关基础知识 1.计算机网络    2 ...

  3. 两个数组的交集 II [ LeetCode - 350 ]

      原题地址:https://leetcode-cn.com/problems/intersection-of-two-arrays-ii/description/   给定两个数组,写一个方法来计算 ...

  4. Ecplise下设置jQuery和ExtJs自动提示

    Spket 1.6.23下载: http://yunpan.cn/cjJYmEcMFIuuN  访问密码 5642 ext jsb下载:http://yunpan.cn/cjJYR7ZTzibQn  ...

  5. 开发中常遇到的Python陷阱和注意点

    最近使用Python的过程中遇到了一些坑,例如用datetime.datetime.now()这个可变对象作为函数的默认参数,模块循环依赖等等. 在此记录一下,方便以后查询和补充. 避免可变对象作为默 ...

  6. oracle11g 使用数据泵导出导入数据

    终于搞定了 快写个笔记 记录下. 删除用户的时候提示已经登录了不能删除,这个需要把登录的session结束掉. select username,sid,serial# from v$session w ...

  7. 【SPOJ - QTREE2】树链剖分

    http://acm.hust.edu.cn/vjudge/problem/19960 题意: 有一棵N个节点的树(1<=N<=10000),N-1条边,边的编号为1~N-1,每条边有一个 ...

  8. 1552: [Cerc2007]robotic sort

    这道题用splay写 先离散化数据保证按题目所述顺序来写 按原序作为键值建树 维护区间最小值去跑 每次将i的位置 和 n的位置x和y找出来后 将x旋转到root y旋转到x的有儿子 这时y的左子树就是 ...

  9. 斜率优化DP讲解

    对于斜率优化的DP转移方程,一般以w[i]=max(w[j]+(sum[i]-sum[j])*v)的1D1D形式为主,直观看来就是前j个为若干个阶段,第j+1到第i个为一个阶段,每个阶段有自己的代价或 ...

  10. HoneyPy 模拟Nginx服务器脚本

    HoneyPy是一个Python写的低交互式蜜罐,可以通过自定义Plugins的方式来配置不同的场景.这里是一个模拟Nginx空白页面的代码: # Auth xiaoxiaoleo # http:// ...