【题解】LOJ2461. 「2018 集训队互测 Day 1」完美的队列
#2461. 「2018 集训队互测 Day 1」完美的队列
\(\text{Solution:}\)
首先需要考虑我们需要知道什么。如果我们知道了一个操作什么时刻被完全删掉,那么就可以做了。
因为题目求的是所有队列的并。
所以我们考虑对序列分块,那么一个操作就会被我们分成覆盖整块的部分和覆盖散块的部分。
那么,一个操作在某个时刻被全部删除,可以从整块和散块两个角度去考虑。
- 整块
如果一个操作被完全删除,那么所有它覆盖了的整块必须被全部删除。
所以我们考虑枚举一个整块,然后枚举上面的所有操作来计算贡献。
这个时候我们发现有隐含的单调性:
对于一个覆盖了当且块的操作 \(v,\) 如果还有一个覆盖了当且块的操作 \(v'\) 且 \(v'>v,\) 那么其结束时间 \(ed(v)\leq ed(v'),\) 证明显然。
所以我们就可以在每一个块上面维护操作上(或者说时间上) 的双指针。当且要处理的时间为 \(L,\) 已经将右指针移动到了 \(R.\) 然后我们不断移动 \(R\) 直到整个块为空。然后 如果 \(L\) 的操作是完全覆盖整块的,就 cmax(ed[L],r)
,否则不能取。
因为只有完全覆盖当前块的操作才有单调性。容易发现,每个操作在每个块上只做了一次,复杂度是 \(O(n\sqrt n)\)
那么如何快速维护一个块是否全部被删除?考虑维护一个当前块内最多还能插入 Mx
个元素就会全部删除,再维护一个全局插入标记 tg
,那么如果整块为空当且仅当 \(Mx-tg<0.\)
那么对于整块覆盖的操作我们可以直接修改 tg,
对于覆盖了当且块的一部分的操作,我们考虑直接暴力整块并更新 tg,Mx
。
这一部分的复杂度:首先容易分析到,所有没有覆盖整块的操作点数之和是 \(O(m\sqrt n)\) 的,因为一个操作最多涉及 \(O(\sqrt n)\) 个散点。
我们对这部分进行暴力修改的复杂度仍然是一个根号。那么整块的处理到此为止。
- 散块
一个操作被分成了若干散块和若干整块,散块怎么做?
首先我们之前已经说过,所有覆盖的散块的点数之和是 \(O(m\sqrt n)\) 的,也就是说,我们需要严格依照这个来做才能保证复杂度。
然后继续考虑有没有隐含性质。容易发现,对于一个位置 \(x,\) 如果一个操作 \(v\) 在 \(x\) 处的结束,那么同样对于 \(v'>v,ed(v')>ed(v),\) 证明同整块。
所以我们发现可以对一个位置做双指针。
那么为了节省空间,我们在处理完当前整块的时候立刻处理所有涉及当前整块的散块的操作。
那么我们将所有没有完全包含当前块的操作序列记下来,然后在这个操作序列上面做双指针。因为这样才能保证上面 \(O(m\sqrt n)\) 的修改点数。设为数组 d[]
.
容易发现我们在处理到 d[r]
的时候,左端点是 d[l],
我们需要知道这一段时间中的所有贡献,这就需要我们维护一个时间上的前缀和,来维护所有不在 d[]
中操作(也就是整块覆盖操作)的贡献。
同时我们还需要定位到哪个时刻这个操作被删空。所以我们记录一个 pk[i]
表示在这个块中,第 \(i\) 个整块覆盖的操作的时间。根据前缀和和维护的对当前点的贡献,我们可以做到 \(O(1)\) 回答这个点值。
要记录的原因是结束的时间点不一定在 d[]
中,有可能是两个 d[i]
相邻的中间一部分。
综上,我们就可以做到一个根号的做法。
那么考虑一些细节:
-
做散块的时候,
Mx
维护的是当前 \(L\) 到 \(R\) 中所有散块的贡献,因此,我们每次做完一个 \(L\) 都需要撤销掉它。撤销掉它对下一个 \([L,R]\) 的影响。 -
两过程中,当左指针右移的时候,需要把左指针的贡献删掉。因为我们只考虑当前左指针到右指针的贡献,所以前面的一概不算。(因为当前左指针是新插入到队列尾端的啊)
其他细节参照代码。
//#include <bits/stdc++.h>
//using namespace std;
//typedef double db;
//#define int long long
//#define fi first
//#define se second
//#define mk make_pair
//#define pb emplace_back
//#define poly vector<int>
//#define Bt(a) bitset<a>
//#define bc __builtin_popcount
//#define pc putchar
//#define ci const int&
//const int mod = 998244353;
//const db eps = 1e-10;
//const int inf = (1 << 30);
//inline int Max(ci x, ci y) {return x > y ? x : y;}
//inline int Min(ci x, ci y) {return x < y ? x : y;}
//inline db Max(db x, db y) {return x - y > eps ? x : y;}
//inline db Min(db x, db y) {return x - y < eps ? x : y;}
//inline int Add(ci x, ci y, ci M = mod) {return (x + y) % M;}
//inline int Mul(ci x, ci y, ci M = mod) {return x*y%M;}
//inline int Dec(ci x, ci y, ci M = mod) {return (x - y + M) % M;}
//typedef pair<int, int> pii;
//inline int Abs(int x) {return x < 0 ? -x : x;}
////char buf[1<<21],*p1=buf,*p2=buf;
////#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char Obuf[105000],*O=Obuf;//Siz shoule be the size of Out File
//int pst[30],ptop;
//inline void Fprint(){fwrite(Obuf,1,O-Obuf,stdout);}
//inline void Fwrite(int x){
// if(x==0){*O++='0';return;}
// if(x<0)*O++='-',x=-x;ptop=0;
// while(x)pst[++ptop]=x%10,x/=10;
// while(ptop)*O++=pst[ptop--]+'0';
// if(O-Obuf>100000)Fprint(),O=Obuf;
//}
//inline int read() {
// int s = 0, w = 1;
// char ch = getchar();
// while (!isdigit(ch)) {if (ch == '-') w = -1;ch = getchar();}
// while (isdigit(ch)) {s = s * 10 + ch - '0';ch = getchar();}
// return s * w;
//}
//inline void write(int x) {
// if (x < 0)putchar('-'), x = -x;
// if (x > 9)write(x / 10);
// pc(x % 10 + '0');
//}
//inline int qpow(int x, int y) {
// int res = 1;
// while (y) {if (y & 1)res = Mul(res, x);x = Mul(x, x);y >>= 1;}
// return res;
//}
//inline void cadd(int &x, int y) {x += y;}
//inline void cmul(int &x, int y) {x *= y;}
//inline void cmax(int &x, int y) {x = Max(x, y);}
//inline void cmin(int &x, int y) {x = Min(x, y);}
//const int N = 1000010;
//namespace Refined_heart{
// int n,m,B;
// int a[N],bl[N];
// struct OPT{
// int l,r,v;
// OPT(int xx=0,int yy=0,int zz=0){
// l=xx;r=yy;v=zz;
// }
// }p[N];
// poly bk[N];
// int t[N],ed[N],sum[N],d[N],pk[N],pre[N];
// void work(int pos){
// int l=1,r=0,Mx=-inf,lpos=bk[pos][0],rpos=0;
// for(int i=0;i<(int)bk[pos].size();++i)t[bk[pos][i]]=a[bk[pos][i]],cmax(Mx,a[bk[pos][i]]),rpos=bk[pos][i];
// int tg=0;sum[0]=0;
// int dcnt=0;
// int zcnt=0;
//// cout<<pos<<" blocksiz:: "<<lpos<<" "<<rpos<<endl;
// while(l<=m&&r<=m){
//// printf("%d:\n",l);
// while(Mx-tg>=0&&r<m){
// ++r;sum[r]=sum[r-1];pre[r]=pre[r-1];
//// printf("[%d %d %d]\n",r,p[r].l,p[r].r);
// if(p[r].r>=rpos&&p[r].l<=lpos&&rpos-lpos+1>=B)tg++,sum[r]++,pk[++zcnt]=r,pre[r]=r;
// else if(p[r].l>rpos||p[r].r<lpos)continue;
// else{
// Mx=-inf;
// for(int i=lpos;i<=rpos;++i){
// t[i]-=tg;
// if(i>=p[r].l&&i<=p[r].r)t[i]--;
// cmax(Mx,t[i]);
// }
// tg=0;
// d[++dcnt]=r;
// }
//// printf("[%d %d %d %d]\n",r,p[r].l,p[r].r,Mx-tg);
//// cout<<"now: "<<Mx<<" "<<tg<<"\n";
// }
//// cout<<r<<" "<<Mx<<" "<<tg<<endl;
//// if(l==2){
//// puts("2-------------------");
//// cout<<"R::"<<r<<endl;
//// cout<<Mx-tg<<endl;
//// cout<<Mx<<" "<<tg<<endl;
//// cout<<lpos<<" "<<rpos<<endl;
//// cout<<p[l].l<<" "<<p[l].r<<endl;
//// puts("_-------------------");
//// }
// if(Mx-tg<0&&(p[l].l<=lpos&&p[l].r>=rpos)){
//// puts("---------------------------");
//// cout<<l<<" "<<r<<endl;
// cmax(ed[l],r);
//// puts("---------------------------");
// if(p[l].l<=lpos&&p[l].r>=rpos)--tg;
// else if(!(p[l].l>rpos||p[l].r<lpos)){
// Mx=-inf;
// for(int i=lpos;i<=rpos;++i){
// t[i]-=tg;
// if(i>=p[l].l&&i<=p[l].r)t[i]++;
// cmax(Mx,t[i]);
// }
// tg=0;
// }
// }
// else if(p[l].l<=lpos&&p[l].r>=rpos)ed[l]=inf;
// if(Mx-tg<0&&(!(p[l].r<lpos||p[l].l>rpos))){
// if(p[l].l<=lpos&&p[l].r>=rpos)--tg;
// else if(!(p[l].l>rpos||p[l].r<lpos)){
// Mx=-inf;
// for(int i=lpos;i<=rpos;++i){
// t[i]-=tg;
// if(i>=p[l].l&&i<=p[l].r)t[i]++;
// cmax(Mx,t[i]);
// }
// tg=0;
// }
// }
//
//// cout<<"ed[l] = "<<ed[l]<<endl;
// l++;
// }
// d[++dcnt]=m+1;sum[m+1]=sum[m];pre[m+1]=pre[m];
// for(int i=0;i<(int)bk[pos].size();++i){
// int now=bk[pos][i];
// l=1,r=0;t[now]=a[now];Mx=t[now];
//// cout<<"pos:: "<< now<<endl;
// int num=0;
// while(l<=dcnt&&r<=dcnt){
//// printf("now l : %d :\n",d[l]);
// while(r<dcnt&&Mx-sum[d[r]]+sum[d[l]-1]>=0){
// ++r;
// if(p[d[r]].l<=now&&p[d[r]].r>=now)Mx--;
// else ++num;
// }
//// printf("now r : %d :\n",d[r]);
//// cout<<"now Mx : "<< Mx -sum[d[r]]+sum[d[l]-1] <<endl;
//// cout<<"mow sum : "<< sum[d[r]]<<endl;
// if(Mx-sum[d[r]]+sum[d[l]-1]<0&&p[d[l]].l<=now&&p[d[l]].r>=now){
// int P=0;
//// int prepos=0;//prepos:pre zhengkuai
// if(p[d[r]].l<=now&&p[d[r]].r>=now)P=d[r];
// else{
//// prepos=pre[d[l]];
// int S=sum[d[l]];
// int cc=sum[d[r]]-sum[d[l]-1];
//// --cc;//l is right
// int cha=-1-(Mx-sum[d[r]]+sum[d[l]-1]);
// cc-=cha;
//// puts("Change----------------");
//// cout<<cha<<endl;
//// cout<<sum[d[r]]-sum[d[l]-1]<<endl;
//// cout<<prepos<<endl;
//// cout<<S+cc<<endl;
//// puts("----------------");
// P=pk[S+cc];
// }
//// cout<<"-_____------- "<<cc<<'\n';
//// printf("---------------------- %d\n",P);
//// cout<<d[l]<<" "<<P<<endl;
//// puts("--------------------");
// cmax(ed[d[l]],P);
// //endpos=d[r]-cc
// Mx=a[now];
//// if(p[d[l]].l<=now&&p[d[l]].r>=now){
//// }
// }
// else if(Mx-sum[d[r]]+sum[d[l]-1]>=0&&p[d[l]].l<=now&&p[d[l]].r>=now)ed[d[l]]=inf;
//// else if(bl[p[d[l]].l]!=bl[p[d[l]].r])ed[d[l]]=inf;
// ++l;
// }
// t[now]=0;
// }
// }
// int vc[N];
// poly endtime[N];
// void solve(){
// n=read();m=read();B=sqrt(n+m);
// for(int i=1;i<=n;++i)a[i]=read(),bl[i]=(i-1)/B+1;
// for(int i=1;i<=m;++i){
// int u=read(),v=read(),w=read();
// p[i]=OPT(u,v,w);
// }
// p[m+1]=OPT(0,0,0);
// for(int i=1;i<=n;++i)bk[bl[i]].pb(i);
// for(int i=1;i<=(n-1)/B+1;++i)work(i);
// for(int i=1;i<=m;++i){
// printf("%d %d\n",i,ed[i]);
// }
// for(int i=1;i<=m;++i)if(ed[i]>m)ed[i]=0;
// for(int i=1;i<=m;++i)if(ed[i])endtime[ed[i]].pb(i);
// int ans=0;
//// for(int i=1;i<=m;++i){
//// printf("%d %d\n",i,ed[i]);
//// }
// for(int i=1;i<=m;++i){
// for(auto v:endtime[i])--vc[p[v].v],ans-=(vc[p[v].v]==0);
// if(!vc[p[i].v])++ans;
// vc[p[i].v]++;
// write(ans);pc('\n');
// }
// }
//}
//signed main(){
// freopen("in.txt","r",stdin);
//// freopen("My.out","w",stdout);
// Refined_heart::solve();
// return 0;
//}
#include <bits/stdc++.h>
using namespace std;
typedef double db;
#define int long long
#define fi first
#define se second
#define mk make_pair
#define pb emplace_back
#define poly vector<int>
#define Bt(a) bitset<a>
#define bc __builtin_popcount
#define pc putchar
#define ci const int&
const int mod = 998244353;
const db eps = 1e-10;
const int inf = (1 << 30);
inline int Max(ci x, ci y) {return x > y ? x : y;}
inline int Min(ci x, ci y) {return x < y ? x : y;}
inline db Max(db x, db y) {return x - y > eps ? x : y;}
inline db Min(db x, db y) {return x - y < eps ? x : y;}
inline int Add(ci x, ci y, ci M = mod) {return (x + y) % M;}
inline int Mul(ci x, ci y, ci M = mod) {return x*y%M;}
inline int Dec(ci x, ci y, ci M = mod) {return (x - y + M) % M;}
typedef pair<int, int> pii;
inline int Abs(int x) {return x < 0 ? -x : x;}
//char buf[1<<21],*p1=buf,*p2=buf;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char Obuf[105000],*O=Obuf;//Siz shoule be the size of Out File
int pst[30],ptop;
inline void Fprint(){fwrite(Obuf,1,O-Obuf,stdout);}
inline void Fwrite(int x){
if(x==0){*O++='0';return;}
if(x<0)*O++='-',x=-x;ptop=0;
while(x)pst[++ptop]=x%10,x/=10;
while(ptop)*O++=pst[ptop--]+'0';
if(O-Obuf>100000)Fprint(),O=Obuf;
}
inline int read() {
int s = 0, w = 1;
char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') w = -1;ch = getchar();}
while (isdigit(ch)) {s = s * 10 + ch - '0';ch = getchar();}
return s * w;
}
inline void write(int x) {
if (x < 0)putchar('-'), x = -x;
if (x > 9)write(x / 10);
pc(x % 10 + '0');
}
inline int qpow(int x, int y) {
int res = 1;
while (y) {if (y & 1)res = Mul(res, x);x = Mul(x, x);y >>= 1;}
return res;
}
inline void cadd(int &x, int y) {x += y;}
inline void cmul(int &x, int y) {x *= y;}
inline void cmax(int &x, int y) {x = Max(x, y);}
inline void cmin(int &x, int y) {x = Min(x, y);}
const int N = 1000010;
namespace Refined_heart{
int n,m,B;
int a[N],bl[N];
struct OPT{
int l,r,v;
OPT(int xx=0,int yy=0,int zz=0){
l=xx;r=yy;v=zz;
}
}p[N];
poly bk[N];
int t[N],ed[N],sum[N],d[N],pk[N],pre[N];
void work(int pos){
int l=1,r=0,Mx=-inf,lpos=bk[pos][0],rpos=0;
for(int i=0;i<(int)bk[pos].size();++i)t[bk[pos][i]]=a[bk[pos][i]],cmax(Mx,a[bk[pos][i]]),rpos=bk[pos][i];
int tg=0;sum[0]=0;
int dcnt=0;
int zcnt=0;
while(l<=m&&r<=m){
while(Mx-tg>=0&&r<m){
++r;sum[r]=sum[r-1];pre[r]=pre[r-1];
if(p[r].r>=rpos&&p[r].l<=lpos&&rpos-lpos+1>=B)tg++,sum[r]++,pk[++zcnt]=r,pre[r]=r;
else if(p[r].l>rpos||p[r].r<lpos)continue;
else{
Mx=-inf;
for(int i=lpos;i<=rpos;++i){
t[i]-=tg;
if(i>=p[r].l&&i<=p[r].r)t[i]--;
cmax(Mx,t[i]);
}
tg=0;
d[++dcnt]=r;
}
}
if(Mx-tg<0&&(p[l].l<=lpos&&p[l].r>=rpos)){cmax(ed[l],r);}
else if(p[l].l<=lpos&&p[l].r>=rpos)ed[l]=inf;
if((!(p[l].r<lpos||p[l].l>rpos))){
if(p[l].l<=lpos&&p[l].r>=rpos)--tg;
else if(!(p[l].l>rpos||p[l].r<lpos)){
Mx=-inf;
for(int i=lpos;i<=rpos;++i){
t[i]-=tg;
if(i>=p[l].l&&i<=p[l].r)t[i]++;
cmax(Mx,t[i]);
}
tg=0;
}
}
l++;
}
d[++dcnt]=m+1;sum[m+1]=sum[m];pre[m+1]=pre[m];pk[++zcnt]=m+1;
for(int i=0;i<(int)bk[pos].size();++i){
int now=bk[pos][i];
l=1,r=0;t[now]=a[now];Mx=t[now];
while(l<=dcnt&&r<=dcnt){
while(r<dcnt&&Mx-sum[d[r]]+sum[d[l]-1]>=0){
++r;
if(p[d[r]].l<=now&&p[d[r]].r>=now)Mx--;
}
if(Mx-sum[d[r]]+sum[d[l]]<0&&p[d[l]].l<=now&&p[d[l]].r>=now){
int P=0;
if(p[d[r]].l<=now&&p[d[r]].r>=now&&Mx-sum[d[r]]+sum[d[l]]==-1)P=d[r];
else{
int S=sum[d[l]];
int cc=sum[d[r]]-sum[d[l]];
int cha=-1-(Mx-sum[d[r]]+sum[d[l]]);
cc-=cha;
if(p[d[r]].l<=now&&p[d[r]].r>=now)++cc;///
if(S+cc<=zcnt)P=pk[S+cc];
else P=inf;
}
// puts("-----------------------");
// cout<<d[l]<<" "<<P<<endl;
// cout<<d[r]<<" "<<endl;
// puts("------------------------");
cmax(ed[d[l]],P);
}
else if(Mx-sum[d[r]]+sum[d[l]-1]>=0&&p[d[l]].l<=now&&p[d[l]].r>=now)ed[d[l]]=inf;
//Mx
if(p[d[l]].l<=now&&p[d[l]].r>=now)++Mx;
++l;
}
t[now]=0;
}
}
int vc[N];
poly endtime[N];
void solve(){
n=read();m=read();B=sqrt(n);
for(int i=1;i<=n;++i)a[i]=read(),bl[i]=(i-1)/B+1;
for(int i=1;i<=m;++i){
int u=read(),v=read(),w=read();
p[i]=OPT(u,v,w);
}
p[m+1]=OPT(0,0,0);
for(int i=1;i<=n;++i)bk[bl[i]].pb(i);
for(int i=1;i<=(n-1)/B+1;++i)work(i);
// for(int i=1;i<=m;++i){
// printf("%lld %lld\n",i,ed[i]);
// }
for(int i=1;i<=m;++i)if(ed[i]>m)ed[i]=0;
for(int i=1;i<=m;++i)if(ed[i])endtime[ed[i]].pb(i);
int ans=0;
for(int i=1;i<=m;++i){
for(auto v:endtime[i])--vc[p[v].v],ans-=(vc[p[v].v]==0);
if(!vc[p[i].v])++ans;
vc[p[i].v]++;
write(ans);pc('\n');
}
}
}
signed main(){
freopen("in.txt","r",stdin);
freopen("My.out","w",stdout);
Refined_heart::solve();
return 0;
}