Description
小D有n个std::queue,他把它们编号为1到n。小D对每个队列有不同的喜爱程度,如果有他不怎么喜欢的队列
占用了太大的内存,小D就会不开心。具体地说,如果第i个队列的size()大于a_i,小D就会对这个队列一直执行
pop()直到其size()小等于a_i。现在这些队列都是空的,小D觉得太单调了,于是他决定做一些操作。 每次操作都可以用l r
x来描述,表示对编号在[l,r]内的所有队列执行push(x)操作。
当然,每次操作结束后,小D都会用之前提到的方法来避免这些队列占用太大的内存。小D的队列很神奇,所以他能
用O(1)的时间执行每次操作。相信大家的队列都能做到,于是小D把这道题出给大家送分。为了证明你确实执行了
这些操作,你需要在每次操作后输出目前还在队列内的权值种数。
Input
第一行两个正整数n,m,分别表示队列个数和操作个数。 第二行n个正整数,第i个表示a_i。 接下来m行,每行三个正整数l r
x,其中第i行表示第i次操作。 对于所有数据,n,m,a_i,x≤10^5。
Output
输出共m行,每行一个非负整数,表示第i次操作结束后所有队列中的权值种数。
Sample Input
3 3
1 2 3
1 2 1
2 3 2
1 3 3
Sample Output
1
2
2
HINT
样例解释
第一次操作后,队列变成{1}{1}{},还在队列内的权值有1,共1种。
第二次操作后,队列变成{1}{1,2}{2},还在队列内的权值1,2,共2种。
第三次操作后,队列变成{3}{2,3}{2,3},还在队列内的权值有2,3,共2种。
题解
集训队胡策还是吼啊
我们只需要知道,对于每个询问,他产生的所有权值最后消失是什么时候
考虑分块
那么对于一个区间,有整块和散块之分
于是我们可以对一个询问考虑整块与散块中,最后一个消失的权值的最大值
分类讨论
对于一个整块,维护 ( j , k ] (j,k] (j,k]两个指针表示做完 [ j , k ] [j,k] [j,k]的操作完后, j j j扔进该块的所有权值都消失了
显然,对于整块的操作,具有单调性
维护一个 c o v cov cov表示当前整个块被覆盖了多少次
然后再维护一个 m x mx mx表示块内最大还要被覆盖多少次才能把 j j j踢掉的次数
那么当 c o v > = m x cov>=mx cov>=mx时, j j j被踢掉了
考虑如何扩展 k k k,当 k k k是整块时,直接把 c o v cov cov加一
否则,暴力枚举块内被第 k k k次操作覆盖了的位置,然后暴力更新 m x mx mx
对于每一个操作,显然最多只会有两个散块,所以暴力更新的部分是 m n m\sqrt n mn的
整块同样也只有 n \sqrt n n个,移端点的部分也是 m n m\sqrt n mn的
对于散块的操作就想不到了啊…
我们显然不能做如上的操作
那么 换个思路 不妨考虑每个位置对散块的贡献?
显然每个询问最多只会被 2 n 2\sqrt n 2n个位置贡献,如果我们能同样用单调性移动就能过了啊
枚举每个位置 u u u,维护 s u m sum sum表示该位置还要被覆盖多少次
维护扫散块的指针 ( j , k ] (j,k] (j,k]表示做完散块 j j j与 k k k之间的操作之后, j j j扔进该块的权值都消失了
思考一下,这个东西同样是满足单调性的…
移动右端点直到 m x ≤ 0 mx\leq 0 mx≤0,然后讨论可得真实的右端点在哪里
因为右端点可能在散块之间的整块中
想着想着就忘了考虑每个数的贡献了啊…
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXN=100005;
struct node
{
int l,r,x,id;
node(){}
node(int _l,int _r,int _x,int _id){l=_l;r=_r;x=_x;id=_id;}
}A[MAXN],B[MAXN],E[MAXN];
vector<node> vec[MAXN];
int n,m,a[MAXN],b[MAXN],block,S[MAXN],T[MAXN],pos[MAXN];
int ed[MAXN],num[MAXN],vis[MAXN],cov,mx;
int sum[MAXN];
struct line
{
int l,r,x;
line(){}
line(int _l,int _r,int _x){l=_l;r=_r;x=_x;}
}w[2*MAXN];
bool cmp(line n1,line n2){return n1.x!=n2.x?n1.x<n2.x:n1.l<n2.l;}
int as[MAXN];
int main()
{
n=read();m=read();block=sqrt(n);
for(int i=1;i<=n;i++)
{
pos[i]=(i-1)/block+1;
if(pos[i]!=pos[i-1])S[pos[i]]=i,T[pos[i-1]]=i-1;
}
T[pos[n]]=n;block=pos[n];
for(int i=1;i<=n;i++)a[i]=b[i]=read();
for(int i=1;i<=m;i++)
{
int l=read(),r=read(),x=read();num[i]=x;
for(int j=pos[l]+1;j<pos[r];j++)vec[j].push_back(node(S[j],T[j],x,i));
if(pos[l]!=pos[r])
{
vec[pos[l]].push_back(node(l,T[pos[l]],x,i));
vec[pos[r]].push_back(node(S[pos[r]],r,x,i));
}
else vec[pos[l]].push_back(node(l,r,x,i));
}
for(int i=1;i<=block;i++)
{
int ln1=0,ln2=0,len=0;sum[1]=0;
for(int j=0;j<vec[i].size();j++)
{
int l=vec[i][j].l,r=vec[i][j].r;
if(l==S[i]&&r==T[i])
{
A[++ln1]=vec[i][j];
sum[ln2+1]++;
if(ln2)E[++len]=vec[i][j];
}
else B[++ln2]=vec[i][j],sum[ln2+1]=0;
}
cov=0;mx=0;
for(int j=S[i];j<=T[i];j++)mx=max(mx,b[j]);
for(int j=0,k=1;j<vec[i].size();j++)
{
if(j!=0)
{
int l=vec[i][j].l,r=vec[i][j].r;
if(l==S[i]&&r==T[i])cov--;
else
{
mx=0;
for(int u=l;u<=r;u++)b[u]++;
for(int u=S[i];u<=T[i];u++)mx=max(mx,b[u]);
}
}
while(k<vec[i].size()&&cov<mx)
{
int l=vec[i][k].l,r=vec[i][k].r;
if(l==S[i]&&r==T[i])cov++;
else
{
mx=0;
for(int u=l;u<=r;u++)b[u]--;
for(int u=S[i];u<=T[i];u++)mx=max(mx,b[u]);
}
k++;
}
if(vec[i][j].l==S[i]&&vec[i][j].r==T[i])
{
if(cov>=mx)ed[vec[i][j].id]=max(ed[vec[i][j].id],vec[i][k-1].id);
else ed[vec[i][j].id]=m+1;
}
}
sum[1]=0;
for(int u=S[i];u<=T[i];u++)
{
cov=a[u];int tot=0;
for(int j=1,k=2;j<=ln2;j++)
{
if(j!=1)
{
cov+=sum[j];
if(B[j].l<=u&&B[j].r>=u)cov++;
}
while(cov>0&&k<=ln2)
{
cov-=sum[k];tot+=sum[k];
if(B[k].l<=u&&B[k].r>=u)cov--;
k++;
}
if(B[j].l<=u&&B[j].r>=u)
{
if(cov>0)
{
if(cov>sum[k])ed[B[j].id]=m+1;
else ed[B[j].id]=max(ed[B[j].id],E[tot+cov].id);
}
else
{
int ls=-cov,pos;//多做了这么多操作
ls-=(B[k-1].l<=u&&B[k-1].r>=u);
if(ls==-1)pos=B[k-1].id;
else pos=E[tot-ls].id;
ed[B[j].id]=max(ed[B[j].id],pos);
}
}
}
}
}
// for(int i=1;i<=m;i++)pr2(ed[i]);
// for(int i=1;i<=m;i++)ed[i]--;
int ln=0;
for(int i=1;i<=m;i++)w[i]=line(i,ed[i]-1,num[i]);
sort(w+1,w+1+m,cmp);
for(int i=1,nxt;i<=m;i=nxt+1)
{
nxt=i;
while(w[nxt+1].x==w[i].x&&nxt<m)nxt++;
int mx=-1,L=0;
for(int j=i;j<=nxt;j++)
{
if(w[j].l>mx)as[L]++,as[mx+1]--,L=w[j].l;
mx=max(mx,w[j].r);
}
as[L]++;as[mx+1]--;
}
as[0]=0;
for(int i=1;i<=m;i++)as[i]+=as[i-1],pr2(as[i]);
return 0;
}