【APIO2018】新家(线段树)
【APIO2018】新家(线段树)
题面
题解
论比赛时想不到二分的危害,就只能Cu滚粗
既然不要在线,那么考虑离线做法。
既然时间是区间,那么显然按照时间顺序处理答案。
显然答案具有可二分性,那么对于当前位置而言,我们唯一要确定的就是\([x-mid,x+mid]\)区间内是否所有种类的商店都至少出现过了一次。
因为离线之后按照时间处理,因此已经没有了时间这一维,只剩下了位置和种类两个东西。那么问题就是二维数点,但是因为要求每个种类只数一次,所以似乎没法直接上树套树。
既然要维护这个东西,显然需要额外记录当前颜色的前驱位置,假装为\(pre_i\)。
发现这样子仍然需要依次考虑每一个颜色,那么我们换一种方法。\(pre_i\)记录的既然是前驱位置,那么考虑\([x+mid+1,inf)\)的每个种类的商店的前驱位置,如果前驱不在\([x-mid,x+mid]\)的区间内,即证明区间内不存在这个种类的商店。既然多个商店可以在同一个位置,所以\(pre_i\)就记录和在\(i\)位置的所有商店中的最小前驱位置。这样子转为对于\((i,pre_i)\)进行二维数点,并且只需要统计点数。
那么考虑如何维护\(pre_i\)的值就好了。
一个显而易见的想法就是对于每个种类开一个\(set\)维护其出现的所有位置。首先维护一下无解的情况,然后因为可能一种颜色并没有在\([x+mid+1,inf)\)范围内出现,所以再额外维护一下每种颜色最后一个位置的最小值就好了。然而实际写的时候并不需要维护最小位置,可以强行在\(inf\)位置上给每个种类强行加一个进来,再在\(-inf\)位置上强制加一个,这样子就不存在没有前驱或者后继的情况了。
最后的二分可以选择在线段树上二分,二分右端点最终直接减一下就是答案了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define ll long long
#define MAX 300300
#define inf 1000000000
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,K,Q,Typecnt,ans[MAX];
struct Work
{
int y;//time
int x,t;//position,type
int opt;//add/del/query
}p[MAX*3];
int tot;
bool operator<(Work a,Work b){if(a.y!=b.y)return a.y<b.y;return a.opt<b.opt;}
multiset<int>::iterator it,itt;
multiset<int> S[MAX],tt[MAX*20];
struct Node{int mn,ls,rs;}t[MAX*20];
int TOT,rt;
void Modify(int &x,int l,int r,int p,int Add,int Del)
{
if(!x)x=++TOT;
if(l==r)
{
if(Add)tt[x].insert(Add);
if(Del)tt[x].erase(tt[x].find(Del));
t[x].mn=(tt[x].empty()?inf:*tt[x].begin());
return;
}
int mid=(l+r)>>1;
if(p<=mid)Modify(t[x].ls,l,mid,p,Add,Del);
else Modify(t[x].rs,mid+1,r,p,Add,Del);
t[x].mn=min(t[t[x].ls].mn,t[t[x].rs].mn);
}
int Query(int p)
{
int l=0,r=inf,x=rt,mn=inf;
while(l<r)
{
int mid=(l+r)>>1,pos=min(t[t[x].rs].mn,mn);
if(p>mid||(mid-p<p-pos))l=mid+1,x=t[x].rs;
else r=mid,x=t[x].ls,mn=pos;
}
return l-p;
}
int main()
{
n=read();K=read();Q=read();t[0].mn=inf;
for(int i=1;i<=n;++i)
{
int x=read(),t=read(),a=read(),b=read();
p[++tot]=(Work){a,x,t,1};
p[++tot]=(Work){b+1,x,t,-1};
}
for(int i=1;i<=Q;++i)
{
int x=read(),y=read();
p[++tot]=(Work){y,x,i,2};
}
sort(&p[1],&p[tot+1]);
for(int i=1;i<=K;++i)S[i].insert(inf),S[i].insert(-inf);
for(int i=1;i<=K;++i)Modify(rt,0,inf,inf,-inf,0);
for(int i=1;i<=tot;++i)
{
int opt=p[i].opt;
if(opt==1)//Add
{
it=itt=S[p[i].t].upper_bound(p[i].x);
--itt;
Modify(rt,0,inf,*it,p[i].x,*itt);
Modify(rt,0,inf,p[i].x,*itt,0);
if(S[p[i].t].size()==2)++Typecnt;
S[p[i].t].insert(p[i].x);
}
else if(opt==-1)//Del
{
it=itt=S[p[i].t].upper_bound(p[i].x);
--itt;--itt;
Modify(rt,0,inf,*it,*itt,p[i].x);
Modify(rt,0,inf,p[i].x,0,*itt);
S[p[i].t].erase(S[p[i].t].find(p[i].x));
if(S[p[i].t].size()==2)--Typecnt;
}
else ans[p[i].t]=Typecnt<K?-1:Query(p[i].x);
}
for(int i=1;i<=Q;++i)printf("%d\n",ans[i]);
return 0;
}
【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\) ...
- BZOJ5462 APIO2018新家(线段树+堆)
一个显然的做法是二分答案后转化为查询区间颜色数,可持久化线段树记录每个位置上一个同色位置,离线后set+树状数组套线段树维护.这样是三个log的. 注意到我们要知道的其实只是是否所有颜色都在该区间出现 ...
- 2015 UESTC 数据结构专题E题 秋实大哥与家 线段树扫描线求矩形面积交
E - 秋实大哥与家 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/contest/show/59 De ...
- [JLOI2014]松鼠的新家(树链剖分)
[JLOI2014]松鼠的新家(luogu) Description 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间 ...
随机推荐
- 个人项目 Individual Project
通讯录中的联系人包含以下信息项:姓名.手机.办公电话.家庭电话.电子邮箱.所在省市.工作单位.家庭住址,群组分类(亲属.同事.同学.朋友.其他). 系统的主要功能包括: 1. 输入联系人的信息,要求: ...
- Python之random模块
random模块 产生随机数的模块 是Python的标准模块,直接导入即可 import random 1)随机取一个整数,使用.randint()方法: import random print(ra ...
- 多线程系列之十:Future模式
一,Future模式 假设有一个方法需要花费很长的时间才能获取运行结果.那么,与其一直等待结果,不如先拿一张 提货单.获取提货单并不耗费时间.这里提货单就称为Future角色获取Future角色的线程 ...
- JavaScript中的各种X,Y,Width,Height
在JavaScript DOM编程中,会接触很多很多很多关于浏览器的宽高,屏幕的宽高,元素的各种宽高,以及鼠标的坐标等,常常让人搞混.索性就写篇博客整理一下. case 1:鼠标的坐标 获取鼠标的坐标 ...
- Nginx会话保持之nginx-sticky-module模块
Nginx会话保持之nginx-sticky-module模块 - 天行健,君子以自强不息:地势坤,君子以厚德载物. - CSDN博客https://blog.csdn.net/huangjinjin ...
- Use the Microsoft Symbol for VS and Windbg
快捷方式mklink的远程符号由于所有者权限问题,链接到本地可能造成不能使用, 或每次都需要重新下载, 1.环境变量中没有设置_NT_SYMBOL_PATH的值 2.windbg快捷方式中也没有设置- ...
- MySQL基础配置之mysql的默认字符编码的设置(my.ini设置字符编码) - 转载
MySQL基础配置之mysql的默认字符编码的设置(my.ini设置字符编码) MySQL的默认编码是Latin1,不支持中文,那么如何修改MySQL的默认编码呢,下面以设置UTF-8为例来说明. 需 ...
- Windows NT 的历史
Windows NT 的版本历史 https://blog.csdn.net/flyingpig2016/article/details/53282895/ 按照自己找到的资料:windows NT ...
- ELK日志系统+x-pack安全验证
根据之前已经搭好的ELK系统,现在加一个x-pack插件上去,不然谁拿到ip和端口都可以访问elasticsearch和kibana. 要的效果如下:打开kibana界面的时候要让其输入用户名密码才能 ...
- 第六周作业----PSP&工作量
1. PSP 日期 类别 工作 开始时间 中断时间 结束时间 总时间 4.7 站立会议 "耐撕"团队站立会议 20:00 20:15 15 重构 重构"抢答器&q ...