写了一种比较容易理解 但是常数很大的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. web前端工程化/构建自动化

    前端工程化 前端工程化的概念在近些年来逐渐成为主流构建大型web应用不可或缺的一部分,在此我通过以下这三方面总结一下自己的理解. 为什么需要前端工程化. 前端工程化的演化. 怎么实现前端工程化. 为什 ...

  2. Django---进阶5

    目录 单表操作 必知必会13条 测试脚本 查看内部sql语句的方式 神奇的双下划线查询 一对多外键增删改查 多对多外键增删改查 正反向的概念 多表查询 子查询(基于对象的跨表查询) 联表查询(基于双下 ...

  3. Report.Net 本地数据库、WebService、Socket报表

    本地.服务器的Access.Sql报表编辑.预览.打印. 可自定义预览界面,可方便嵌入到你的程序中去,提供接口函数,如有需要可自行添加接口. 预览采用单双面方式,因为如果页面过多,预览不能全部加载,所 ...

  4. scala 数据结构(一):数据结构简介

    1 数据结构特点 scala集合基本介绍 1)Scala同时支持不可变集合和可变集合,不可变集合可以安全的并发访问 2)两个主要的包: 不可变集合:scala.collection.immutable ...

  5. 数据可视化之powerBI技巧(十三)PowerBI作图技巧:动态坐标轴

    之前的文章中介绍了如何制作动态的分析指标,这篇进行文章再介绍一下如何制作动态的坐标轴. 假设要分析的数据为销售额,分别从产品和地区两个维度进行分析,要实现的效果是,如果选择的是产品,则坐标轴是各个产品 ...

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

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

  7. js 中 attachEvent 简示例

    attachEvent绑定事件,函数的默认this指向为window,要解决问题可以通过call改变方法的指向! var div = document.getElementsByTagName('di ...

  8. Ethical Hacking - GAINING ACCESS(4)

    SERVER SIDE ATTACKS - METASPLOIT Metasploit is an exploit development and execution tool. It can als ...

  9. 集训作业 洛谷P1010 幂次方

    这个…… 这个题看上去有点难的样子. 仔细看看,感觉有点简单.啊,是递归啊,正经的看一看,好像是把一个数分成2的几次方的和. 然后余数和比他小的最大的2的次方数如果不是2的一次方或者2的0次方,就继续 ...

  10. 关于Java8的精心总结

    前言 ​ 最近公司里比较新的项目里面,看到了很多关于java8新特性的用法,由于之前自己对java8的新特性不是很了解也没有去做深入研究,所以最近就系统的去学习了一下,然后总结了一篇文章第一时间和大家 ...