【LOJ2461】「2018 集训队互测 Day 1」完美的队列(分块+双指针)
大致题意: 让你维护\(n\)个有限定长度的队列,每次区间往队列里加数,求每次加完后的队列里剩余元素种类数。
核心思路
这道题可以用分块+双指针去搞。
考虑求出每个操作插入的元素在队列中被全部弹完所需要的时间\(Max_i\),最后差分即可求出答案。
我们可以\(O(\sqrt n)\)枚举块,然后\(O(m)\)枚举询问,从而统计每一个块对每一个询问的贡献值。
因此,我们主要要考虑的,就是分别对于整块与非整块,如何求出其对于一个询问的贡献。
整块对询问的贡献
整块对询问的贡献应该是比较好统计的。
考虑记录一个\(tot\)表示整个块被完全覆盖的次数,并开一个数组\(t\)表示每个队列还需要被覆盖多少次才能把当前数弹掉(初始化:\(t_i=a_i\))。
然后,我们用一个变量\(Mx\)维护\(t\)的最大值,则对于一个覆盖整块的操作,它会被全部弹完,当且仅当\(Mx\le tot\)。
由于这个被全部弹完的时间显然是递增的,因此我们可以用双指针来维护,即固定当前正在处理的操作为左端点,然后移动右端点使得\(Mx\le tot\)。
则对于一个整块操作,若移动右端点,则我们将\(tot\)加\(1\),反之减\(1\)。
对于一个非整块操作,若移动右端点,则我们将操作范围内的\(t_i\)减\(1\),反之加\(1\),同时重新求一遍\(Mx\)。
移动完后,我们将当前左端点的\(Max\)值向当前右端点的位置取\(max\)即可。
这样,我们就处理完了整块对询问的贡献。
非整块对询问的贡献
这就略微麻烦了。
为了处理这个,我们要先在前面处理整块的时候维护一些信息:
- \(Sum_i\):维护在前\(i\)个操作中有多少个覆盖整块的操作。
- \(Cov_i\):记录第\(i\)个覆盖整块的操作的时间。
- \(NCov_i\):记录第\(i\)个没有覆盖整块但与这个整块有交集的操作的时间。
- \(Pos_i\):记录第\(i\)个没有覆盖整块的操作的上一个覆盖整块操作的时间。
接下来,考虑枚举块内的每一个位置,然后枚举每一个非整块操作,统计贡献。
让我们来思考一下,如何求出某一操作在什么时候会被弹完。
实际上我们可以继续使用双指针。
我们重新初始化一个\(Mx\)为当前枚举到位置的\(a_i\),然后统计右端点与左端点之间有多少个覆盖整块的操作(用\(Sum\)相减即可)以及有多少个覆盖第\(i\)个位置的非整块操作(双指针可以轻松维护这一信息),并用\(Mx\)减去这两个值。
显然,当一次操作被弹完了,当且仅当\(Mx\le0\)。
但注意这里用来更新左端点\(Max\)的值就不一定是右端点的位置了,因为有可能它是在右端点与上一个非整块操作间的某一个整块操作时弹完的,这就需要分类讨论了,具体实现详见代码。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define SN 400
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define Gmax(x,y) (x<(y)&&(x=(y)))
using namespace std;
int n,m,s,a[N+5],v[N+5],t[N+5],cnt[N+5],Sum[N+5],Cov[N+5],NCov[N+5],Pos[N+5];
struct Op {int l,r,v,Mx;}o[N+5];
struct Event
{
int t,v,op;I Event(CI _t=0,CI _v=0,CI _op=0):t(_t),v(_v),op(_op){}
I bool operator < (Con Event& o) Con {return t<o.t;}
}e[(N<<1)+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
I void clear() {fwrite(FO,1,C,stdout),C=0;}
}F;
I void BlockSolve(CI l,CI r)//求解一个块对答案的贡献
{
#define Cover(x) (o[x].l<=l&&r<=o[x].r)//判断第x个操作是否覆盖当前块
#define Intersect(x) (o[x].l<=r&&l<=o[x].r)//判断第x个操作是否与当前块有交集
#define ReBuild() for(Mx=0,i=l;i<=r;++i) Gmax(Mx,t[i]);//重构块,即重求Mx
#define Update(x,op)\
{\
if(Cover(x)) tot+=op;else if(Intersect(x))\
{\
for(i=max(l,o[x].l),lim=min(r,o[x].r);i<=lim;++i) t[i]-=op;\
ReBuild();\
}\
}//加入/删除一次操作,分覆盖整块与有交集两种情况讨论
RI i,Mx,lim,tot=0,H=1,T=0,cc=0,ncc=0;
ReBuild();for(H=1;H<=m;++H)//处理整块对询问的贡献
{
Update(H,-1);W(T<=m&&Mx>tot) {++T;Update(T,1);}//移动双指针端点
Sum[H]=Sum[H-1],Cover(H)?(Gmax(o[H].Mx,T),++Sum[Cov[++cc]=H])//统计前缀和,对于整块处理
:Intersect(H)&&(NCov[++ncc]=H,Pos[ncc]=cc);//存储下有交集的块的信息
}
#undef Cover
#define Cover(x) (o[NCov[x]].l<=i&&i<=o[NCov[x]].r)//重新定义Cover为第x个操作是否覆盖当前枚举的位置
for(i=l;i<=r;++i) for(Mx=a[i],H=1,T=0;H<=ncc;++H)//枚举位置和非整块操作
{
if(Mx+=Sum[NCov[H]]-Sum[NCov[H-1]],!Cover(H)) continue;//统计Mx,如果不覆盖则跳过
++Mx;W(T^ncc&&Mx>0) ++T,Mx-=Sum[NCov[T]]-Sum[NCov[T-1]],Cover(T)&&--Mx;//移动双指针端点
Mx>0?(Sum[m]-Sum[NCov[T]]>=Mx?Gmax(o[NCov[H]].Mx,Cov[Pos[T]+Mx]):(o[NCov[H]].Mx=m+1))//分类讨论更新答案
:Gmax(o[NCov[H]].Mx,Cover(T)?(Mx?Cov[Pos[T]+Mx+1]:NCov[T]):Cov[Pos[T]+Mx]);
}
}
int main()
{
RI i,p,ans=0;for(F.read(n,m),s=sqrt(n),i=1;i<=n;++i) F.read(a[i]),t[i]=a[i];//初始化t[i]为a[i]
for(i=1;i<=m;++i) F.read(o[i].l,o[i].r,o[i].v);//读入
for(i=1;i<=n/s;++i) BlockSolve((i-1)*s+1,i*s);n%s&&(BlockSolve(n/s*s+1,n),0);//分块处理答案
for(i=1;i<=m;++i) e[(i<<1)-1]=Event(i,o[i].v,1),e[i<<1]=Event(o[i].Mx,o[i].v,-1);//差分
for(sort(e+1,e+(m<<1)+1),p=i=1;i<=m;++i)//枚举时间
{
W(p<=(m<<1)&&e[p].t==i) !cnt[e[p].v]&&++ans,!(cnt[e[p].v]+=e[p].op)&&--ans,++p;//更新答案
F.writeln(ans);//输出答案
}return F.clear(),0;
}
【LOJ2461】「2018 集训队互测 Day 1」完美的队列(分块+双指针)的更多相关文章
- @loj - 2461@ 「2018 集训队互测 Day 1」完美的队列
目录 @description@ @solution@ @part - 0@ @part - 1@ @accepted code@ @details@ @description@ 小 D 有 n 个 ...
- 【loj2461】【2018集训队互测Day 1】完美的队列
#2461. 「2018 集训队互测 Day 1」完美的队列 传送门: https://loj.ac/problem/2461 题解: 直接做可能一次操作加入队列同时会弹出很多数字,无法维护:一个操作 ...
- LOJ2476. 「2018 集训队互测 Day 3」蒜头的奖杯 & LOJ2565. 「SDOI2018」旧试题(莫比乌斯反演)
题目链接 LOJ2476:https://loj.ac/problem/2476 LOJ2565:https://loj.ac/problem/2565 题解 参考照搬了 wxh 的博客. 为了方便, ...
- LOJ3069. 「2019 集训队互测 Day 1」整点计数(min_25筛)
题目链接 https://loj.ac/problem/3069 题解 复数真神奇. 一句话题意:令 \(f(x)\) 表示以原点 \((0, 0)\) 为圆心,半径为 \(x\) 的圆上的整点数量, ...
- [JZOJ6088] [BZOJ5376] [loj #2463]【2018集训队互测Day 1】完美的旅行【线性递推】【多项式】【FWT】
Description Solution 我们考虑将问题一步步拆解 第一步求出\(F_{S,i}\)表示一次旅行按位与的值为S,走了i步的方案数. 第二步答案是\(F_{S,i}\)的二维重复卷积,记 ...
- 【2018集训队互测】【XSY3372】取石子
题目来源:2018集训队互测 Round17 T2 题意: 题解: 显然我是不可能想出来的……但是觉得这题题解太神了就来搬(chao)一下……Orzpyz! 显然不会无解…… 为了方便计算石子个数,在 ...
- 洛谷 P4463 - [集训队互测 2012] calc(多项式)
题面传送门 & 加强版题面传送门 竟然能独立做出 jxd 互测的题(及其加强版),震撼震撼(((故写题解以祭之 首先由于 \(a_1,a_2,\cdots,a_n\) 互不相同,故可以考虑求出 ...
- EZ 2018 05 06 NOIP2018 慈溪中学集训队互测(五)
享受爆零的快感 老叶本来是让初三的打的,然后我SB的去凑热闹了 TM的T2写炸了(去你妹的优化),T1连-1的分都忘记判了,T3理所当然的不会 光荣革命啊! T1 思维图论题,CHJ dalao给出了 ...
- 【纪中集训2019.3.27】【集训队互测2018】小A的旅行(白)
题目 描述 \(0-n-1\)的图,满足\(n\)是\(2\)的整数次幂, $ i \to j $ 有 $ A_{i,j} $ 条路径: 一条路径的愉悦值定义为起点和终点编号的\(and\)值 ...
随机推荐
- cmake指令详解
所需文件名:CmakeLists.txt,在需要操作的每个目录下都需要 PROJECT(工程名字) 这条指令会自动创建两个变量: <projectname>_BINARY_DIR( ...
- 用poi替换ppt中的文字和图片
try { // 获取PPT文件 String pptModelPath =ConfigReadUtil.getInstance().getConfigI ...
- js动态给textarea赋值
document.getElementById("new_analysed_news").value=datas.weatherContent;
- vue-scroller的使用 && 开发自己的 scroll 插件
vue-scroller的使用 在spa开发过程中,难免会遇到使用scroll的情况,比如下面的: 即,当用户选择好商品之后,点击购物车,就会有一个购物车弹窗,如果选择的商品小于三个,刚好合适,如果多 ...
- java多态简单例子
/* 对象的多态性:动物 x = new 猫(); 函数的多态性:函数重载.重写 1.多态的体现 父类的引用指向了自己的子类对象 父类的引用也可以接收自己的对象 2.多态的前提 必须是类与类之间只有关 ...
- 让 framset 框架中的页面全屏显示
<script type="text/javascript"> window.onload=function(){ if(window.parent!=window){ ...
- 案例42-使用ajax获取crm中的客户列表
1webcontent部分 1 修改menu.jsp代码 2 jsp/customer/list.jsp代码 <%@ page language="java" content ...
- 转-------基于R-CNN的物体检测
基于R-CNN的物体检测 原文地址:http://blog.csdn.net/hjimce/article/details/50187029 作者:hjimce 一.相关理论 本篇博文主要讲解2014 ...
- Python的静态方法和类成员方法都可以被类或实例访问,两者概念不容易理清,但还是有区别的
转:http://www.cnblogs.com/2gua/ Python的静态方法和类成员方法都可以被类或实例访问,两者概念不容易理清,但还是有区别的: 1)静态方法无需传入self参数,类成员方法 ...
- 如何给MySql创建连接用户并授权
一般在为MySql创建用户时建议使用GRANT前台命令,当然如果对我们开发者而言,方法还有很多种,比如使用INSERT命令,甚至是直接修改mysql user数据表,但仍然建议按照MySQL规范去授权 ...