【題解/學習筆記】回滾莫隊

回滾莫隊是對付一類操作難以撤回的莫隊做法。

從例題開始。

【模板】回滾莫隊&不刪除莫隊

題目要求區間中相同數的最大座標差,顯然地這個東西撤回是很難的。

那麼考慮回滾莫隊是如何做這件事情的:

首先我們把詢問分塊,然後將詢問的左端點所在塊作爲第一關鍵字,把右端點置爲第二關鍵字。

經過上述排序後我們發現,左端點在同一個塊內的詢問,右端點都是遞增的。也就是說,我們在處理左端點在同一個塊內的詢問的時候,右端點可以保證不會進行撤回操作。

那麼考慮左端點如何做?

由於我們發現,區間長度是 \(O(\sqrt{n})\) 的,所以我們考慮一種暴力的做法:每次把左指針 \(l\) 暴力拉回去,重新掃。

那麼我們面臨的問題就是如何把指針拉回去。我們考慮,在增加指針的時候,記錄下指針的變化,也就是加入這個數的前置狀態,然後我們按順序把這個前置狀態還原回去即可。

那麼其具體流程如下:

  • 對詢問排序

    • 若當前詢問的左端點塊編號和上一次詢問的不同
      • 令左指針爲當前左端點塊右端點 \(+1,\) 右指針爲當前左端點塊右端點。
    • (注意要先進行上面的判斷,保證指針移動到位) 如果當前詢問的左右端點在同一個塊中,直接暴力解決。(因爲這種詢問按照上述初始化是計算不到的)
    • 若不在同一個塊裏面,就先讓右端點移過去,再移動左端點,計算答案之後,將狀態還原。

容易發現複雜度是對的:因爲右端點的複雜度正常,而每次詢問左端點的移動次數都不超過 \(O(\sqrt{n})\)

於是題目得解。

例題:AT1219 歴史の研究

同上述流程維護莫隊,維護一個 cnt 記錄次數即可,要記錄的前驅狀態就是答案和顏色。

模板代碼:

#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 = 1e9 + 7;
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 1ll * 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 = 2e5 + 10;
namespace Refined_heart{
	int bl[N],n,a[N],b[N],blen,m,siz;
	struct Node{int lv,rv,pans,vl;Node(int x_=0,int y_=0,int z_=0,int ww_=0){lv=x_,rv=y_,pans=z_,vl=ww_;}};
	vector<Node>v;
	struct QR{
		int l,r,id;
		QR(int xx=0,int yy=0,int zz=0){
			l=xx;
			r=yy;
			id=zz;
		}
	}q[N];
	inline bool cmp(QR x,QR y){
		if(bl[x.l]==bl[y.l])return x.r<y.r;
		return bl[x.l]<bl[y.l];
	}
	inline int getpos(int x){return lower_bound(b+1,b+blen+1,x)-b;}
	int rp[N],lp[N],rans[N];
	int Ans=0;
	void add(int now){
		v.pb(Node(lp[a[now]],rp[a[now]],Ans,a[now]));
		cmin(lp[a[now]],now);
		cmax(rp[a[now]],now);
		cmax(Ans,rp[a[now]]-lp[a[now]]);
	}
	int cl[N],cr[N];
	void calc(int l,int r,int nop){
		int ans=0;
		for(int i=l;i<=r;++i){
			cmax(cr[a[i]],i);
			cmin(cl[a[i]],i);
			cmax(ans,cr[a[i]]-cl[a[i]]);
		}
		for(int i=l;i<=r;++i)cr[a[i]]=0,cl[a[i]]=inf;
		rans[nop]=ans;
	}
	void solve(){
		n=read();
		for(int i=1;i<=n;++i)a[i]=read();
		for(int i=1;i<=n;++i)b[i]=a[i];
		sort(b+1,b+n+1);
		blen=unique(b+1,b+n+1)-b-1;
		for(int i=1;i<=n;++i)a[i]=getpos(a[i]);
		m=read();
		for(int i=1;i<=m;++i)q[i].l=read(),q[i].r=read(),q[i].id=i;
		siz=sqrt(n);
		for(int i=1;i<=n;++i)bl[i]=((i-1)/siz)+1;
		sort(q+1,q+m+1,cmp);
		memset(lp,0x3f,sizeof lp);
		memset(cl,0x3f,sizeof cl);
		int l=1,r=0;bl[0]=-1;
		for(int i=1;i<=m;++i){
			int ql=q[i].l;
			int qr=q[i].r;
			if(bl[ql]!=bl[q[i-1].l]){
				int pos=bl[ql]*siz;
				r=pos;l=pos+1;
				while(!v.empty()){
					Node now=v.back();
					v.pop_back();
					int val=now.vl;
					lp[val]=inf,rp[val]=0;
				}
				Ans=0;
			}
			if(bl[ql]==bl[qr]){
				calc(ql,qr,q[i].id);
				continue;
			}
			while(r<qr)add(++r);
			while(l>ql)add(--l);
			rans[q[i].id]=Ans;
			while(l<bl[ql]*siz+1){
				Node now=v.back();
				v.pop_back();
				int val=now.vl;
				++l;
				lp[val]=now.lv;
				rp[val]=now.rv;
				Ans=now.pans;
			}
		}
		for(int i=1;i<=m;++i)Fwrite(rans[i]),*O++='\n';
		Fprint();
	}
}
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 = 1e9 + 7;
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 1ll * 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 = 2e5 + 10;
namespace Refined_heart{
	int n,a[N],m,siz,bl[N];
	int b[N],blen;
	struct QR{
		int l,r,id;
	}q[N];
	struct Node{
		int col,pans;
		Node(int x_=0,int y_=0){
			col=x_;
			pans=y_;
		}
	};
	vector<Node>rub;
	int Ans=0,rans[N];
	inline int getpos(int x){return lower_bound(b+1,b+blen+1,x)-b;}
	inline bool cmp(QR x,QR y){
		if(bl[x.l]==bl[y.l])return x.r<y.r;
		return bl[x.l]<bl[y.l];
	}
	int ct[N],cnt[N];
	void solve_(int l,int r,int op){
		int ans=0;
		for(int i=l;i<=r;++i)ct[a[i]]++,cmax(ans,b[a[i]]*ct[a[i]]);
		for(int i=l;i<=r;++i)ct[a[i]]=0;
		rans[op]=ans;
	}
	void add(int now){
		Node pt=Node(a[now],Ans);rub.pb(pt);
		cnt[a[now]]++;cmax(Ans,b[a[now]]*cnt[a[now]]);
	}
	void solve(){
		n=read();m=read();
		for(int i=1;i<=n;++i)a[i]=read();
		siz=sqrt(n);
		for(int i=1;i<=n;++i)bl[i]=(i-1)/siz+1;
		for(int i=1;i<=m;++i){
			q[i].l=read();
			q[i].r=read();
			q[i].id=i;
		}
		sort(q+1,q+m+1,cmp);
		for(int i=1;i<=n;++i)b[i]=a[i];
		sort(b+1,b+n+1);
		blen=unique(b+1,b+n+1)-b-1;
		for(int i=1;i<=n;++i)a[i]=getpos(a[i]);
		int l=1,r=0;
		for(int i=1;i<=m;++i){
			int ql=q[i].l;
			int qr=q[i].r;
			if(bl[ql]!=bl[q[i-1].l]){
				int pos=bl[ql]*siz;
				l=pos+1;
				r=pos;
				while(!rub.empty()){
					Node v=rub.back();
					rub.pop_back();
					cnt[v.col]=0;
				}
				Ans=0;
			}
			if(bl[ql]==bl[qr]){
				solve_(ql,qr,q[i].id);
				continue;
			}
			while(r<qr)add(++r);
			while(l>ql)add(--l);
			rans[q[i].id]=Ans;
			while(l<bl[ql]*siz+1){
				Node v=rub.back();
				rub.pop_back();
				++l;
				cnt[v.col]--;
				Ans=v.pans;
			}
		}
		for(int i=1;i<=m;++i)write(rans[i]),pc('\n');
	}
}
signed main(){
	freopen("in.txt","r",stdin);
	Refined_heart::solve();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章