LOJ2461. 「2018 集訓隊互測 Day 1」完美的佇列
阿新 • • 發佈:2021-07-11
有\(n\)個佇列,每個佇列上限是\(a_i\)。如果佇列超過上限就彈隊頭。
每次給\([l,r]\)的佇列加入顏色\(x\)。
問所有時間中,存在於至少一個佇列的顏色的個數。
\(n\le 10^5\)
好題。
離線。現在考慮求出一個操作的存活時間區間。
分塊,把操作拆成整塊操作和散塊操作,分別計算其存活時間並取max。
顯然,如果兩種操作操作區間相同,那麼前者比後者死得早。根據這個單調性搞搞事情:
求整塊操作的存活時間:
如果固定一個整塊操作,在剛操作時令\(h_i=a_i\);後面每次別的操作(整塊或散塊)操作能使得一些\(h_i\)減一。如果\(\max(h_i)\le 0\),則這個整塊操作剛好死亡。
根據單調性,在這個整塊操作死去之後,計算下一個整塊操作前先繼承一些資訊。顯然要\(h_i\)加上兩者間對佇列\(i\)的操作次數。如果兩者間存在散塊操作,就可以掃整個塊暴力更新,因為複雜度可以攤到其中任意一個散塊上;如果不存在散塊操作,就打個區間加一的標記。
求散塊操作的存活時間:
對於散點分別維護個佇列,佇列中每個元素除了記操作編號之外,還有它被加入時整塊操作加入過多少個。於是就可以得知兩個散塊操作之間,一共進行了多少次操作。最後用個雙指標掃過去就可以得到每個散塊操作的存活時間。
時間\(O(n\sqrt n)\)。
並不是很好實現,整塊和散塊之間的各類影響錯綜複雜,寫的時候要好好整理一下。
精細實現2h左右,幾乎沒有除錯,交上去沒有WA,倒是一車的MLE。經過重重卡空間終於過去了……
using namespace std; #include <bits/stdc++.h> #define fi first #define se second #define mp make_pair const int N=100005,B=400,INF=1000000000; int n,m; int a[N],c[N]; struct Itv{int l,r;} p[N]; int mx[N]; vector<int> o[N]; void upd(int t,int r){mx[t]=max(mx[t],r);} int buc[N]; int bel[N],R[N],nb; struct info{int t,z;}; int sz,firb,hp[B+5],cd; vector<info> qb; vector<int> qd[B+5]; int zd[N]; int h[B+5],mxh,tag; void reset_h(int lst){ mxh=-INF; for (int i=1;i<=sz;++i){ while (hp[i]<qd[i].size() && zd[qd[i][hp[i]]]==lst) hp[i]++,h[i]++; mxh=max(mxh,h[i]+tag); } } void adjust(int t){ if (firb<qb.size() && mxh<=0){ info f=qb[firb++]; upd(f.t,t); if (firb<qb.size()){ info g=qb[firb]; if (g.z) reset_h(firb); mxh++,tag++; } } } void mdf_d(int st,int en,int t){ if (st>en) return; cd++; zd[t]=qb.size(); for (int i=st;i<=en;++i){ h[i]--; qd[i].push_back(t); } mxh=-INF; for (int i=1;i<=sz;++i) mxh=max(mxh,h[i]+tag); adjust(t); } void mdf_b(int t,int os){ mxh--,tag--; adjust(t); if (firb==qb.size()){ mxh=-INF; for (int i=1;i<=sz;++i){ mxh=max(mxh,h[i]=a[os+i]); hp[i]=qd[i].size(); } tag=0; } qb.push_back({t,cd}); cd=0; } void workd(int d,int ad){ for (int i=0,j=0;i<qd[d].size();++i){ while (j<qd[d].size() && (zd[qd[d][j]]+j)-(zd[qd[d][i]]+i)<=ad) ++j; int tmp=(zd[qd[d][i]]+i+ad)-(zd[qd[d][j-1]]+j-1); if (tmp==0) upd(qd[d][i],qd[d][j-1]); else{ tmp+=zd[qd[d][j-1]]; upd(qd[d][i],(tmp<=qb.size()?qb[tmp-1].t:m+1)); } } } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) scanf("%d",&a[i]); for (int i=1;i<=n;++i) bel[i]=(i-1)/B+1,R[bel[i]]=i,nb=bel[i]; for (int i=1;i<=m;++i) scanf("%d%d%d",&p[i].l,&p[i].r,&c[i]); for (int i=1;i<=nb;++i){ sz=R[i]-R[i-1]; qb.clear(); for (int j=1;j<=sz;++j) qd[j].clear(),h[j]=hp[j]=0; firb=cd=mxh=tag=0; for (int t=1;t<=m;++t) if (p[t].l<=R[i-1]+1 && R[i]<=p[t].r) mdf_b(t,R[i-1]); else mdf_d(max(p[t].l,R[i-1]+1)-R[i-1],min(p[t].r,R[i])-R[i-1],t); for (;firb<qb.size();++firb) upd(qb[firb].t,m+1); for (int j=1;j<=sz;++j) workd(j,a[j+R[i-1]]); } for (int i=1;i<=m;++i){ o[i].push_back(c[i]); o[mx[i]].push_back(-c[i]); } int ans=0; for (int i=1;i<=m;++i){ for (int j=0;j<o[i].size();++j){ int x=abs(o[i][j]),c=(o[i][j]>0?1:-1); ans-=(buc[x]!=0); buc[x]+=c; ans+=(buc[x]!=0); } printf("%d\n",ans); } return 0; }