一个显然的做法是二分答案后转化为查询区间颜色数,可持久化线段树记录每个位置上一个同色位置,离线后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新家(线段树+堆)的更多相关文章

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

    其实这个题第一反应一定是线段树分治,但是这样反而更难考虑了(实际上是可做的但很难想到),可见即使看上去最贴切的算法也未必能有效果. 考虑这个DS题,没有什么模型的转化,可能用到的无非就是线段树.平衡树 ...

  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. 关于MSCOCO_text数据集的探索

    最近需要做图片中文本识别的项目,然后为了快速验证模型,所以找到了mscoco-text数据集,网站1上是这么说的: 官网是这么说的: 然而,我下下来之后: 1 - 先导入: 2 - 其中key为'im ...

  2. Swoole Task 的应用

    目录 概述 代码 小结 扩展 参考文档 概述 Swoole 异步Task,主要实现调用异步任务的执行. 常用的场景:异步支付处理.异步订单处理.异步日志处理.异步发送邮件/短信等. Swoole 的实 ...

  3. 从0开始学golang--2.1--如何去爬园子的数据

    20天过去了,才开始写...主要还是因为自己懒吧.之前一边上班一边也有挤时间练习golang,可是写博客却老是不能行动,跑步也没跑了.突然的就懈怠了快一个月.可能也和开始玩the elder scro ...

  4. 20155304田宜楠《网络对抗技术》Exp1 PC平台逆向破解(5)M

    Exp1 PC平台逆向破解(5)M 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 该程序 ...

  5. 20155308《网络对抗》Exp4 恶意代码分析

    20155308<网络对抗>Exp4 恶意代码分析 实践说明 实践目标 是监控你自己系统的运行状态,看有没有可疑的程序在运行. 是分析一个恶意软件,就分析Exp2或Exp3中生成后门软件: ...

  6. IIS发布问题

    下午发布一个IIS ,出现一个很奇葩的问题,在本地跑代码运行都正常,但是发布到IIS上后 访问提示: CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framewo ...

  7. python 回溯法 子集树模板 系列 —— 13、最佳作业调度问题

    问题 给定 n 个作业,每一个作业都有两项子任务需要分别在两台机器上完成.每一个作业必须先由机器1 处理,然后由机器2处理. 试设计一个算法找出完成这n个任务的最佳调度,使其机器2完成各作业时间之和达 ...

  8. maven 相关问题

    maven 这里要更新完 不一定非要clean install  那个出问题了再弄,一般刷新一下maven仓库就行了,最好还是用自己配置的maven,不容易出问题

  9. 【ORACLE】Win2008R2修改oracle数据库实例名

    需求说明:要求将windows平台的数据库实例名由orcl改为haha 参考: https://www.cnblogs.com/junnor/archive/2013/03/05/2945245.ht ...

  10. LeetCode Merge k Sorted Lists (链表)

    题意 Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity ...