写了一种比较容易理解 但是常数很大的sol.

容易发现可以扫描线。

维护好序列之后发现很难查距离 考虑二分。

这里二分可以在线段树上进行 当然可能存在一些问题 如果离散化的话需要处理一些比较麻烦的细节 如:需要向左二分一次向右二分一次什么的。

当然也可以直接在外面二分 得到一个区间 发现只要区间的本质不同的颜色满足 K种判定即可成功。

在线数颜色一般使用线段树+树状数组。不过这样做事log^3的。

考虑判定区间的另外一种方式 我们只需要所有颜色在这个区间中即可。 可以发现 如果总颜色不足k种 就GG.

发现某种颜色的最右端点小于当前区间 GG.这个东西可以开一个set维护。

考虑之后所颜色都在这个区间加后缀的一段区间内 考虑后续的一段区间内的pre的最小值 如果在这个区间之外 那么GG 反之 可以发现所有颜色都在当前区间内。

由于存在重复的值 考虑线段树上每个节点再开一个set维护重复的信息。

这样总复杂度为(n+Q)log^2.

常数较大 开o2后快很多。不过写的时候防止出错在插入一个点删除一个点的时候分类讨论了 写的有点麻烦。可以简单的将几个操作给合并。

注意线段树空间开8倍。

const int MAXN=300010;
int n,Q,k,num,cnt,cc,sum;
struct wy
{
int l,r;
int sum;
}t[MAXN<<3];
struct jl
{
int l,k;//时间
int x,op;//坐标,类型
inline int friend operator <(jl a,jl b){return a.l==b.l?a.k>b.k:a.l<b.l;}
}s[MAXN<<2];
int b[MAXN<<1],ans[MAXN];
multiset<int>v[MAXN],ss;//存放每个颜色的位置集合 ss维护全局颜色的最右端点
multiset<int>g[MAXN<<3];//线段树上每个节点下吊一个set维护pre的最小值
multiset<int>::iterator it,itt,tt,pp;
inline void discrete()
{
sort(b+1,b+1+num);
rep(1,num,i)if(i==1||b[i]!=b[i-1])b[++cnt]=b[i];
}
inline void build(int p,int l,int r)
{
l(p)=l;r(p)=r;sum(p)=INF;
if(l==r)return;
int mid=(l+r)>>1;
build(zz,l,mid);
build(yy,mid+1,r);
}
inline void del(int p,int x,int w)
{
if(l(p)==r(p))
{
pp=g[p].find(b[w]);
g[p].erase(pp);
if(!g[p].size())sum(p)=INF;
else sum(p)=*g[p].begin();
return;
}
int mid=(l(p)+r(p))>>1;
if(x<=mid)del(zz,x,w);
else del(yy,x,w);
sum(p)=min(sum(zz),sum(yy));
}
inline void change(int p,int x,int w)
{
if(l(p)==r(p))
{
g[p].insert(b[w]);
sum(p)=*g[p].begin();
return;
}
int mid=(l(p)+r(p))>>1;
if(x<=mid)change(zz,x,w);
else change(yy,x,w);
sum(p)=min(sum(zz),sum(yy));
}
inline void modify(int p,int x,int w1,int w2)
{
if(l(p)==r(p))
{
pp=g[p].find(b[w1]);
g[p].erase(pp);
g[p].insert(b[w2]);
sum(p)=*g[p].begin();
return;
}
int mid=(l(p)+r(p))>>1;
if(x<=mid)modify(zz,x,w1,w2);
else modify(yy,x,w1,w2);
sum(p)=min(sum(zz),sum(yy));
}
inline void del(int x,int op)//删除在x位置上类型为op的商店
{
//更新全局右端点 更新线段树 更新sum 更新前驱
it=v[op].find(x);
if(it==v[op].begin())
{
del(1,x,0);
if(it==--v[op].end())//无前驱无后继
{
--sum;
itt=ss.find(b[x]);
ss.erase(itt);
}
else//无前驱有后继
{
itt=it;++itt;
modify(1,*itt,x,0);
}
}
else
{
itt=it;--itt;
del(1,x,*itt);
if(it==--v[op].end())//有前驱无后继
{
tt=ss.find(b[x]);
ss.erase(tt);
ss.insert(b[*itt]);
}
else//有前驱有后继
{
tt=it;++tt;
modify(1,*tt,x,*itt);
}
}
v[op].erase(it);
}
inline void insert(int x,int op)//插入
{
//更新全局右端点 更新线段树 更新sum 更新前驱
v[op].insert(x);
it=v[op].find(x);
if(it==v[op].begin())
{
change(1,x,0);
if(it==--v[op].end())//无前驱无后继
{
++sum;ss.insert(b[x]);
}
else//无前驱有后继
{
itt=it;++itt;
modify(1,*itt,0,x);
}
}
else
{
itt=it;--itt;
change(1,x,*itt);
if(it==--v[op].end())//有前驱无后继
{
ss.insert(b[x]);
tt=ss.find(b[*itt]);
ss.erase(tt);
}
else//有前驱有后继
{
tt=it;++tt;
modify(1,*tt,*itt,x);
}
}
}
inline int ask(int p,int l,int r)
{
if(l<=l(p)&&r>=r(p))return sum(p);
int mid=(l(p)+r(p))>>1;
int ww=INF;
if(l<=mid)ww=min(ww,ask(zz,l,r));
if(r>mid)ww=min(ww,ask(yy,l,r));
return ww;
}
inline int check(int x,int w)//查询 x+w+1~n 之中颜色的前驱最小值和 颜色右端点最小值是否大于等于x-mid
{
int R=lower_bound(b+1,b+1+cnt,b[x]+w+1)-b;
int ww=R>cnt?INF:ask(1,R,cnt);
if(!ww)return 0;
ww=min(*ss.begin(),ww);
return ww>=b[x]-w;
}
inline void ask(int x,int id)//坐标 编号
{
if(sum!=k){ans[id]=-1;return;}
int l=0,r=b[cnt];
while(l<r)
{
int mid=(l+r)>>1;
if(check(x,mid))r=mid;
else l=mid+1;
}
ans[id]=l;
}
int main()
{
freopen("1.in","r",stdin);
get(n);get(k);get(Q);//k是类型 Q是询问.
rep(1,n,i)
{
++cc;
get(s[cc].x);get(s[cc].op);
get(s[cc].l);s[cc].k=1;
++cc;s[cc].x=s[cc-1].x;s[cc].op=s[cc-1].op;
get(s[cc].l);s[cc].k=-1;b[++num]=s[cc].x;
}
rep(1,Q,i)
{
get(s[++cc].x);get(s[cc].l);
s[cc].op=i;
b[++num]=s[cc].x;
}
discrete();
sort(s+1,s+1+cc);
build(1,1,cnt);
rep(1,cc,i)
{
s[i].x=lower_bound(b+1,b+1+cnt,s[i].x)-b;
if(!s[i].k)ask(s[i].x,s[i].op);
else
{
if(s[i].k==-1)del(s[i].x,s[i].op);
else insert(s[i].x,s[i].op);
}
}
rep(1,Q,i)put(ans[i]);
return 0;
}

luogu P4632 [APIO2018] New Home 新家 线段树 set 二分的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. [Luogu 3258] JLOI2014 松鼠的新家

    [Luogu 3258] JLOI2014 松鼠的新家 LCA + 树上差分. 我呢,因为是树剖求的 LCA,预处理了 DFN(DFS 序),于是简化成了序列差分. qwq不讲了不讲了,贴代码. #i ...

  7. Luogu 3373 又乘又加的线段树

    Luogu 3373 又乘又加的线段树 当给一个节点加上一个加法标记时,直接把加法标记 += 新值: 当给一个节点加上一个乘法标记时,把乘法标记和加法标记同时 *= 新值.(注意pushdown函数中 ...

  8. luoguP6619 [省选联考 2020 A/B 卷]冰火战士(线段树,二分)

    luoguP6619 [省选联考 2020 A/B 卷]冰火战士(线段树,二分) Luogu 题外话1: LN四个人切D1T2却只有三个人切D1T1 很神必 我是傻逼. 题外话2: 1e6的数据直接i ...

  9. 【BZOJ4552】排序(线段树,二分答案)

    [BZOJ4552]排序(线段树,二分答案) 题面 BZOJ 题解 好神的题啊 直接排序我们做不到 怎么维护? 考虑一下,如果我们随便假设一个答案 怎么检验它是否成立? 把这个数设成\(1\),其他的 ...

随机推荐

  1. POJ 3463 Sightseeing 题解

    题目 Tour operator Your Personal Holiday organises guided bus trips across the Benelux. Every day the ...

  2. Poj 3613 Cow Relays (图论)

    Poj 3613 Cow Relays (图论) 题目大意 给出一个无向图,T条边,给出N,S,E,求S到E经过N条边的最短路径长度 理论上讲就是给了有n条边限制的最短路 solution 最一开始想 ...

  3. efcore 跨表查询,实现一个接口内查询两个不同数据库里各自的表数据

    最近有efcore跨库查询的需求,研究了下colder框架里文档的分库实现,发现并不能完全实现一个接口下的跨库查询请求,只能满足一个业务层构造指定的唯一一个数据库访问接口. 先说下文档是怎么实现的 D ...

  4. 机器学习实战基础(十四):sklearn中的数据预处理和特征工程(七)特征选择 之 Filter过滤法(一) 方差过滤

    Filter过滤法 过滤方法通常用作预处理步骤,特征选择完全独立于任何机器学习算法.它是根据各种统计检验中的分数以及相关性的各项指标来选择特征 1 方差过滤 1.1 VarianceThreshold ...

  5. Python之爬虫(二十一) Scrapy爬取所有知乎用户信息(下)

    在上一篇文章中主要写了关于爬虫过程的分析,下面是代码的实现,完整代码在:https://github.com/pythonsite/spider items中的代码主要是我们要爬取的字段的定义 cla ...

  6. XSS原理及代码分析

    前言 XSS又叫跨站脚本攻击,是一种对网站应用程序的安全漏洞攻击技术.它允许恶意用户将代码注入网页,其他用户在浏览网页时就会受到影响.XSS分为三种:反射型,存储型,和DOM型.下面我会构造有缺陷的代 ...

  7. 老司机带你玩转面试(1):缓存中间件 Redis 基础知识以及数据持久化

    引言 今天周末,我在家坐着掐指一算,马上又要到一年一度的金九银十招聘季了,国内今年上半年受到 YQ 冲击,金三银四泡汤了,这就直接导致很多今年毕业的同学会和明年毕业的同学一起参加今年下半年的秋招,这个 ...

  8. IOS10 window.navigator.geolocation.getCurrentPosition 无法定位问题

    在iOS 10中,苹果对webkit定位权限进行了修改,所有定位请求的页面必须是https协议的. 如果是非https网页,在http协议下通过HTML5原生定位接口会返回错误,也就是无法正常定位到用 ...

  9. J.U.C体系进阶(四):juc-sync 同步器框架

    Java - J.U.C体系进阶 作者:Kerwin 邮箱:806857264@qq.com 说到做到,就是我的忍道! juc-sync 同步器框架 同步器名称 作用 CountDownLatch 倒 ...

  10. row_number() over()排序功能说明

    1.row_number() over()排序功能: (1) row_number() over()分组排序功能: 在使用 row_number() over()函数时候,over()里头的分组以及排 ...