我们考虑对每个询问 求出一个 ,表示在执行完 的操作后, 在序列里加入的所有 全部被pop出去了,就可以对每个颜色 求出若干个存在的区间,将这些区间取并,即可差分贡献到答案
现在考虑怎么求
我们将原序列分块,操作
覆盖了若干个整块和0/1/2个散块,我们分开考虑整块和散块对
的贡献
设操作
加入了元素
对于整块,我们枚举每个块,维护两个指针
,表示当前考虑的操作是
令
表示位置
再被push
次后就会将
pop掉
cov表示这个块被完整覆盖了cov次
mx-cov<=0时就代表这个块内的所有
都被pop出去了,此时
就可以对
产生贡献
考虑怎么维护,新加入一个操作时,若他完整覆盖了这个块,
++,否则若他和这个块有交,交集部分的
- -,然后直接扫一遍整个块更新
,撤销操作类似
每个操作贡献至多
,这部分的复杂度是
的
对于散块,我们需要在处理整块的时候先处理一些东西:
令
表示操作1~
完整覆盖了当前块
次
表示第
个完整覆盖当前块的操作
表示第
个不完整覆盖当前块,但和当前块有交的操作
表示
的
里面最小的
然后我们枚举整块里的每个位置
,考虑他作为被散块覆盖的贡献
在
上维护双指针
,表示当前考虑的操作是
,维护一个
表示位置
当前被覆盖的次数
对于每个
,
不断往后跳直到
,mx可以用前缀和及操作
是否覆盖
直接更新,然后根据mx是否=0,操作
是否覆盖
,是可以用上面处理的几个数组
找到位置
的
被pop出去的时刻的
这部分的复杂度只跟每个块的
的大小有关,每个操作对贡献
个
,所以这部分的复杂度也是
的
所以总复杂度是 的
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define pb push_back
#define mp make_pair
#define SZ(x) (int)x.size()
#define fir first
#define sec second
using namespace std;
inline void read(int &x)
{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void up(int &a,const int &b){if(a<b)a=b;}
const int maxn = 210000;
int n,m,N;
int a[maxn],b[maxn];
int l[maxn],r[maxn],X[maxn],ed[maxn];
int s[maxn];
int c[maxn],cn,d[maxn],dn,e[maxn];
vector< pair<int,int> >V[maxn];
int f[maxn];
int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);
read(n); read(m); N=sqrt(n);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=m;i++) read(l[i]),read(r[i]),read(X[i]);
for(int L=1;L<=n;L+=N)
{
int R=min(L+N-1,n);
int mx=0; for(int i=L;i<=R;i++) up(mx,b[i]=a[i]);
cn=dn=0;
for(int j=1,k=0,cov=0;j<=m;j++)
{
if(l[j]<=L&&r[j]>=R) cov--;
else if(l[j]<=R&&r[j]>=L)
{
for(int i=max(l[j],L),ui=min(r[j],R);i<=ui;i++) b[i]++;
mx=0; for(int i=L;i<=R;i++) up(mx,b[i]);
}
while(k<=m&&mx-cov>0)
{
++k;
if(l[k]<=L&&r[k]>=R) cov++;
else if(l[k]<=R&&r[k]>=L)
{
for(int i=max(l[k],L),ui=min(r[k],R);i<=ui;i++) b[i]--;
mx=0; for(int i=L;i<=R;i++) up(mx,b[i]);
}
}
s[j]=s[j-1];
if(l[j]<=L&&r[j]>=R) up(ed[j],k),s[c[++cn]=j]++;
else if(l[j]<=R&&r[j]>=L) d[++dn]=j,e[dn]=cn;
}
for(int i=L;i<=R;i++)
{
mx=a[i];
for(int j=1,k=0;j<=dn;j++)
{
mx+=s[d[j]]-s[d[j-1]];
if(l[d[j]]<=i&&r[d[j]]>=i)
{
mx++;
while(k<dn&&mx>0) ++k,mx-=s[d[k]]-s[d[k-1]]+(l[d[k]]<=i&&r[d[k]]>=i);
if(mx>0)
{
if(mx>s[m]-s[d[k]]) ed[d[j]]=m+1;
else up(ed[d[j]],c[e[k]+mx]);
continue;
}
if(l[d[k]]<=i&&r[d[k]]>=i) up(ed[d[j]],mx<0?c[e[k]+mx+1]:d[k]);
else up(ed[d[j]],c[e[k]+mx]);
}
}
}
}
//for(int i=1;i<=m;i++) printf("%d\n",ed[i]);
for(int i=1;i<=m;i++) V[X[i]].pb(mp(i,1)),V[X[i]].pb(mp(ed[i],-1));
for(int i=1;i<=100000;i++)
{
sort(V[i].begin(),V[i].end());
int now=0;
for(int j=0;j<SZ(V[i]);j++)
{
int lnow=now;
now+=V[i][j].sec;
for(int k=j+1;k<SZ(V[i])&&V[i][k].fir==V[i][j].fir;k++)
now+=V[i][k].sec,j=k;
if(lnow==0&&now>0) f[V[i][j].fir]++;
else if(lnow>0&&now==0) f[V[i][j].fir]--;
}
}
for(int i=1,ans=0;i<=m;i++) printf("%d\n",(ans+=f[i]));
return 0;
}