#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;
}