一个显然的做法是二分答案后转化为查询区间颜色数,可持久化线段树记录每个位置上一个同色位置,离线后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. 八款开源 Android 游戏引擎 (巨好的资源)

    转载地址:http://software.intel.com/zh-cn/blogs/2012/01/13/android-4 初学Android游戏开发的朋友,往往会显得有些无所适从,他们常常不知道 ...

  2. jqgrid 宽度自适应

    当jqgrid所在操作区宽度大于了给各列设置宽度之和时,此时表格的宽度未铺满操作区,效果不理想 此时,可以通过配置宽带自适应来现实表格内容自动铺满. 配置属性 shrinkToFit:ture 若要启 ...

  3. Python开发简单爬虫

    简单爬虫框架: 爬虫调度器 -> URL管理器 -> 网页下载器(urllib2) -> 网页解析器(BeautifulSoup) -> 价值数据 Demo1: # codin ...

  4. 关于mydumper的.metadata文件丢失

    今天要进行MySQL的数据迁移,所以把数据库通过mydumper工具备份的文件解压后.通过myloader进行导入 可是导入的时间出现这个报错: ** (myloader:766): CRITICAL ...

  5. 【LeetCode206】Reverse Linked List★

    题目描述: 解题思路: 关于单链表的反转有迭代和递归两种方法,方法不在多,本文主要介绍迭代的方法. 迭代的方法,要使用三个指针,需要注意一点的是指针的初始化,对第一个指针初始化为pre=null,第二 ...

  6. C# show FTP Download/Upload progress

    https://stackoverflow.com/questions/4591059/download-file-from-ftp-with-progress-totalbytestoreceive ...

  7. 20155229《网络对抗技术》Exp2:后门原理与实践

    实验预习 后门: 指绕过安全控制而获取对程序或系统访问权的方法.最主要目的就是方便以后再次秘密进入或者控制系统. 木马与后门的区别: 木马:通过欺骗用户的方法(包含捆绑,利用网页等)让用户不知不觉的安 ...

  8. powersheel远程连接方法操作

    powersheel远程连接密码加密连接高级玩法 ConvertTo-SecureString 和 ConvertFrom-SecureString 命令都支持选项 -Key.在处理密码时通过使用 K ...

  9. SCC的奇葩算法——Kosaraju

    不会Tarjan,难道就不能与邪恶的SCC作斗争了吗? 祭出Kosaraju. 一些变量名的意义: a[N] 原图的vector存储 b[N] 原图的所有边反向vector存储 s dfs得出的拓扑序 ...

  10. typedef你真的理解么?

    typedef,用最简单的话去诠释他,那么就是给类型取别名!!!  但是他并没有你想象的那么简单! 举例: typedef int size;//那么int就有一个别名叫size了,以后就可以 siz ...