首先考虑可以用二分答案来解决询问,可以二分一个长度\(len\),若在区间\([x-len,x+len]\)内包含了所有\(k\)种的商店,那么这个\(len\)就是合法的,可以通过二分来求其最小值。

对每个商店的存在时间转化为在\(a\)时刻出现,在\(b+1\)时刻消失,然后和询问一起离线按时间排序,就可以解决时间这一维的限制了。

然后考虑如何快速查询区间内是否包含所有的商店,和支持维护商店的出现消失。

对于这种区间数颜色的问题,可以对每个位置记录与其商店类型相同的上一个位置\(pre\),发现一个位置上可能会有多个商店,那么这里的\(pre\)改为记录这些商店的到其各自商店类型相同的上一个位置的最小值。

\(pre\)是记录该位置商店类型相同的上一个位置,所以对于区间\([l,r]\),如果从\(r+1\)往后的所有位置的\(pre\)的最小值小于\(l\),那么说明至少有一种商店没在该区间出现。但是\(r+1\)往后可能并不会包含所有\(k\)种商店,因此加入哨兵商店来避免讨论,分别在最前面和最后面加入每种商店各一个。

然后就是如何支持维护\(pre\),对于每个位置开一个\(multiset\)维护该位置所有商店的对应其商店类型的前驱,\(multiset\)中的最小值即为该位置的\(pre\),然后用线段树动态开点来维护区间\(pre\)的最小值,这里其实就是在线段树的每个叶子节点开了一个\(multiset\)来维护信息。

对于商店的出现消失维护,对每种商店类型开一个\(multiset\),维护该类型所有商店的出现位置,然后出现和消失只用解决对于该位置同类型的前驱和后继的影响就行,线段树单点修改即可实现。

若用线段树查询最小值来判定二分,复杂度是\(O(n\ log^2\ n)\)的,可以直接在线段树上二分位置,复杂度就是\(O(n\ log\ n)\)的了。

细节挺多,具体实现就看代码吧。

\(code:\)

#include<bits/stdc++.h>
#define maxn 900010
#define all 200000000
#define mid ((l+r)>>1)
using namespace std;
typedef multiset<int>::iterator muli;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,k,q,tot,root,tree_cnt,num;
int mi[maxn*20],ls[maxn*20],rs[maxn*20],ans[maxn];
multiset<int> p[maxn],s[maxn*20];
struct node
{
int pos,tim,id,opt;
}t[maxn];
bool cmp(const node &a,const node &b)
{
if(a.tim==b.tim) return a.opt<b.opt;
return a.tim<b.tim;
}
void modify(int l,int r,int pos,int v,int type,int &cur)
{
if(!cur) cur=++tree_cnt;
if(l==r)
{
if(type) s[cur].insert(v);
else s[cur].erase(s[cur].find(v));
if(!s[cur].empty()) mi[cur]=*s[cur].begin();
else mi[cur]=all;
return;
}
if(pos<=mid) modify(l,mid,pos,v,type,ls[cur]);
else modify(mid+1,r,pos,v,type,rs[cur]);
mi[cur]=min(mi[ls[cur]],mi[rs[cur]]);
}
int query(int pos)
{
if(num<k) return -1;
int l=1,r=all,cur=root,midmi,rmi=all;
while(l<r)
{
midmi=min(rmi,mi[rs[cur]]);
if(pos>mid||midmi<2*pos-mid) cur=rs[cur],l=mid+1;
else rmi=midmi,cur=ls[cur],r=mid;
}
return l-pos;
}
int main()
{
read(n),read(k),read(q),mi[0]=all;
for(int i=1;i<=k;++i)
{
p[i].insert(-all),p[i].insert(all);
modify(1,all,all,-all,1,root);
}
for(int i=1;i<=n;++i)
{
int x,id,a,b;
read(x),read(id),read(a),read(b);
t[++tot]=(node){x,a,id,1};
t[++tot]=(node){x,b+1,id,0};
}
for(int i=1;i<=q;++i)
{
int pos,tim;
read(pos),read(tim);
t[++tot]=(node){pos,tim,i,2};
}
sort(t+1,t+tot+1,cmp);
for(int i=1;i<=tot;++i)
{
int opt=t[i].opt,id=t[i].id,pos=t[i].pos;
muli a,b;
if(opt==0)
{
a=b=p[id].lower_bound(pos),a--,b++;
modify(1,all,*b,pos,0,root);
modify(1,all,*b,*a,1,root);
modify(1,all,pos,*a,0,root);
if(p[id].size()==3) num--;
p[id].erase(p[id].find(pos));
}
if(opt==1)
{
a=b=p[id].lower_bound(pos),a--;
modify(1,all,*b,pos,1,root);
modify(1,all,*b,*a,0,root);
modify(1,all,pos,*a,1,root);
if(p[id].size()==2) num++;
p[id].insert(pos);
}
if(opt==2) ans[id]=query(pos);
}
for(int i=1;i<=q;++i) printf("%d\n",ans[i]);
return 0;
}

题解 洛谷 P4632 【[APIO2018] New Home 新家】的更多相关文章

  1. 洛谷P4632 [APIO2018] New Home 新家(动态开节点线段树 二分答案 扫描线 set)

    题意 题目链接 Sol 这题没有想象中的那么难,但也绝对不简单. 首先把所有的询问离线,按照出现的顺序.维护时间轴来处理每个询问 对于每个询问\((x_i, y_i)\),可以二分答案\(mid\). ...

  2. 洛谷 P3258 [JLOI2014]松鼠的新家 题解

    P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...

  3. 洛谷 P3258 [JLOI2014]松鼠的新家(树链剖分)

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

  4. 洛谷P3258 [JLOI2014]松鼠的新家(树上差分+树剖)

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

  5. 洛谷 P3258 [JLOI2014]松鼠的新家 解题报告

    P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...

  6. 洛谷P3258 [JLOI2014]松鼠的新家

    P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...

  7. 洛谷——P3258 [JLOI2014]松鼠的新家

    https://www.luogu.org/problem/show?pid=3258 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到 ...

  8. 洛谷 P3258 [JLOI2014]松鼠的新家 树链剖分+差分前缀和优化

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 说明 思路 AC代码 优化 优化后AC代码 总结 题面 题目链接 P3258 [JLOI2 ...

  9. 题解——洛谷P4095 [HEOI2013]Eden 的新背包问题(背包)

    思路很妙的背包 用了一些前缀和的思想 去掉了一个物品,我们可以从前i-1个和后i+1个推出答案 奇妙的思路 #include <cstdio> #include <algorithm ...

随机推荐

  1. Python3-configparser模块-配置文件解析器

    Python3中的configparser模块主要用于处理类似于windows ini 文件结构的配置文件 1.configparser模块提供实现基本配置语言的ConfigParser类 2.配置文 ...

  2. Github仓库如何选择开源许可证

    Github仓库如何选择开源许可证 目录 Github仓库如何选择开源许可证 为什么需要开源许可证? 不使用开源许可证对于开发者有何影响? 不使用开源许可证对于项目的使用者有何影响? Github的开 ...

  3. .NET Core加解密实战系列之——消息摘要与数字签名算法

    目录 简介 功能依赖 消息摘要算法 MD算法 家族发展史 应用场景 代码实现 MD5 示例代码 SHA算法 应用场景 代码实现 SHA1 SHA256 示例代码 MAC算法 HMAC算法的典型应用 H ...

  4. 用JQuery解析获取JSON数据

    JSON 是一种比较方便的数据形式,下面使用$.getJSON方法,实现获得JSON数据和解析,都挺方便简单的.从http://api.flickr.com/services/feeds/photos ...

  5. 【spring boot】spring boot 拦截器

    今日份代码: 1.定义拦截器 import com.alibaba.fastjson.JSON; import org.apache.commons.collections.CollectionUti ...

  6. 113资讯网——NGINX 502 Bad Gateway——解决方案

    NGINX 502 Bad Gateway错误出现的原因较多,对于后端连接PHP服务的场景下,常见的原因有php服务响应超时,php进程不足等引起的一类服务器错误. 发生原因: PHP FastCGI ...

  7. java语言基础(七)_继承_super_this_抽象类

    继承 1. 继承概述 2. 继承格式 在继承的关系中,"子类就是一个父类".也就是说,子类可以被当做父类看待. 例如父类是员工,子类是讲师,那么"讲师就是一个员工&quo ...

  8. activiti6基础01-如何数据库操作及相关表

    官网文档:https://www.activiti.org/userguide/#queryAPI 1. Activit的简单源码解读      activiti的官方文档讲解详细很详细,也很范.按着 ...

  9. UVA1464 Traffic Real Time Query System

    传送门:https://www.luogu.com.cn/problem/UVA1464 看到这道题,求必经的点数,还是无向图.那么妥妥的圆方树.圆方树上的任意两圆点间的路径必定是圆点方点相交错的,对 ...

  10. Scala 面向对象(八):特质(接口) 一

    1 Scala接口的介绍 从面向对象来看,接口并不属于面向对象的范畴,Scala是纯面向对象的语言,在Scala中,没有接口. Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说, ...