1. 程式人生 > 其它 >LOJ2461. 「2018 集訓隊互測 Day 1」完美的佇列

LOJ2461. 「2018 集訓隊互測 Day 1」完美的佇列

\(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;
}