点此看题面

大致题意: 让你维护\(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」完美的队列(分块+双指针)的更多相关文章

  1. @loj - 2461@ 「2018 集训队互测 Day 1」完美的队列

    目录 @description@ @solution@ @part - 0@ @part - 1@ @accepted code@ @details@ @description@ 小 D 有 n 个 ...

  2. 【loj2461】【2018集训队互测Day 1】完美的队列

    #2461. 「2018 集训队互测 Day 1」完美的队列 传送门: https://loj.ac/problem/2461 题解: 直接做可能一次操作加入队列同时会弹出很多数字,无法维护:一个操作 ...

  3. LOJ2476. 「2018 集训队互测 Day 3」蒜头的奖杯 & LOJ2565. 「SDOI2018」旧试题(莫比乌斯反演)

    题目链接 LOJ2476:https://loj.ac/problem/2476 LOJ2565:https://loj.ac/problem/2565 题解 参考照搬了 wxh 的博客. 为了方便, ...

  4. LOJ3069. 「2019 集训队互测 Day 1」整点计数(min_25筛)

    题目链接 https://loj.ac/problem/3069 题解 复数真神奇. 一句话题意:令 \(f(x)\) 表示以原点 \((0, 0)\) 为圆心,半径为 \(x\) 的圆上的整点数量, ...

  5. [JZOJ6088] [BZOJ5376] [loj #2463]【2018集训队互测Day 1】完美的旅行【线性递推】【多项式】【FWT】

    Description Solution 我们考虑将问题一步步拆解 第一步求出\(F_{S,i}\)表示一次旅行按位与的值为S,走了i步的方案数. 第二步答案是\(F_{S,i}\)的二维重复卷积,记 ...

  6. 【2018集训队互测】【XSY3372】取石子

    题目来源:2018集训队互测 Round17 T2 题意: 题解: 显然我是不可能想出来的……但是觉得这题题解太神了就来搬(chao)一下……Orzpyz! 显然不会无解…… 为了方便计算石子个数,在 ...

  7. 洛谷 P4463 - [集训队互测 2012] calc(多项式)

    题面传送门 & 加强版题面传送门 竟然能独立做出 jxd 互测的题(及其加强版),震撼震撼(((故写题解以祭之 首先由于 \(a_1,a_2,\cdots,a_n\) 互不相同,故可以考虑求出 ...

  8. EZ 2018 05 06 NOIP2018 慈溪中学集训队互测(五)

    享受爆零的快感 老叶本来是让初三的打的,然后我SB的去凑热闹了 TM的T2写炸了(去你妹的优化),T1连-1的分都忘记判了,T3理所当然的不会 光荣革命啊! T1 思维图论题,CHJ dalao给出了 ...

  9. 【纪中集训2019.3.27】【集训队互测2018】小A的旅行(白)

    题目 描述 ​ \(0-n-1\)的图,满足\(n\)是\(2\)的整数次幂, $ i \to j $ 有 $ A_{i,j} $ 条路径: ​ 一条路径的愉悦值定义为起点和终点编号的\(and\)值 ...

随机推荐

  1. Xtts v4变化&先决条件&已知问题

    V4变化的主要有:     1.这个采购使用简化的命令.源的一个命令(--backup)和目标的一个命令(--restore). 2.此过程只需要在源和目标的$ TMPDIR(res.txt)之间复制 ...

  2. mysql 查询及 删除表中重复数据

    CREATE TABLE `test` ( `id` INT(20) NOT NULL AUTO_INCREMENT, `name` VARCHAR(20) NULL DEFAULT NULL, `a ...

  3. kpw2使用心得

    一:截屏 只需要同时按下对角线的两个点(比如左下角,右上角)就可以,图片可以通过数据线连接到电脑,在根目录下就可以查看截屏图片. 二:拖曳电子书pdf 可以通过数据线连接,找到kpw2的磁盘,将pdf ...

  4. s-2、charles 入门

    本文的内容主要包括: Charles 的简介 如何安装 Charles 将 Charles 设置成系统代理 Charles 主界面介绍 过滤网络请求 截取 iPhone 上的网络封包 截取 Https ...

  5. DEM、DSM、DOM 名词解释

    1.DEM(Digital Elevation Matrix) 数字高程矩阵. 数字高程模型(Digital Elevation Model,缩写DEM)是一定范围内规则格网点的平面坐标(X,Y)及其 ...

  6. Java学习第二十四天

    1:多线程(理解) (1)JDK5以后的针对线程的锁定操作和释放操作 Lock锁 (2)死锁问题的描述和代码体现 (3)生产者和消费者多线程体现(线程间通信问题) 以学生作为资源来实现的 资源类:St ...

  7. 前端测试框架 puppeteer 文档翻译

    puppeteer puppeteer 是一个通过DevTools 协议提供高级API 来控制 chrome,chromium 的 NODE库; puppeteer默认运行在 headless 模式, ...

  8. js中判断对象是否存在

    s中判断对象是否存在,写法有很多种: 第一种:if (!myObj) { var myObj = { }; }第二种:var global = this;  if (!global.myObj) {  ...

  9. vs文件属性(复制到输出目录)是什么意思

    右击项目里的文件,选择属性(F4)会有复制到输出目录的选项. 它提供三项选择,如图: 如果选择始终复制或如果较新则复制会在该程序集的bin目录下生成该文件,如图:

  10. Redis的Publish/Subscribe

    Publish/Subscribe 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布 ...