题解 青蛙题

传送门

沈老师有个神仙爆标做法:
考虑一个特别的 \(O(n^2)\) 做法:
\(nxt_i\)\(i\) 后面第一个与 \(i\) 同色的位置
对于一个询问 \([l, r]\),先预处理出在左端点处的 \(val=\max\{nxt_i\mid nxt_i\leqslant r\}\)
这个可以用 set 实现
然后暴力依次枚举 \(l'\in[l, r]\),考虑将 \(l'\) 删去后 \(val\) 会和 \(nxt_{l'}\) 取 max
那么只有单调栈中的 \(l'\) 是有用的
在单调栈上倍增可以得到需要的信息
但是我懒得写倍增了,它过了,那就不管了
复杂度 \(O(n\log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 2000010
#define fir first
#define sec second
#define pb push_back
#define ll long long
#define ull unsigned long long
//#define int long long

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++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, q;
int a[N], lim;

namespace force{
	vector<int> tem;
	const ull base=13131;
	int lst[N], l[N], r[N];
	ull pw[N], h[N], bit[N];
	vector<pair<int, int>> que[N];
	unordered_map<ull, int> mp[50005];
	inline void upd(int i, ull dat) {for (; i<=n; i+=i&-i) bit[i]+=dat;}
	inline ull query(int i) {ull ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
	void solve() {
		pw[0]=1;
		for (int i=1; i<=lim; ++i) pw[i]=pw[i-1]*base;
		for (int i=1; i<=q; ++i) {
			l[i]=read(); r[i]=read();
			que[l[i]].pb({r[i], i});
		}
		for (int i=n; i; --i) {
			// cout<<"i: "<<i<<endl;
			if (lst[a[i]]) {
				for (auto it=tem.begin(); it!=tem.end(); ++it) if (*it==lst[a[i]]) {
					tem.erase(it); break;
				}
				upd(lst[a[i]], -pw[a[i]]);
			}
			upd(lst[a[i]]=i, pw[a[i]]);
			tem.pb(i);
			// tem.clear();
			// for (int j=1; j<=lim; ++j) if (lst[j]) tem.pb(lst[j]);
			// sort(tem.begin(), tem.end());
			// reverse(tem.begin(), tem.end());
			// cout<<"tem: "; for (auto it:tem) cout<<it<<' '; cout<<endl;
			ull val=0;
			for (int j=(int)tem.size()-1; ~j; --j) mp[i][val+=pw[a[tem[j]]]]=tem[j]; //, cout<<"val: "<<val<<' '<<*it<<endl;
			for (auto& it:que[i]) h[it.sec]=query(it.fir);
		}
		for (int i=1,l,r; i<=q; ++i) {
			l=force::l[i], r=force::r[i];
			int ans=r-l+1;
			// cout<<h[i]<<endl;
			for (int j=l,pos; j<=r; ++j) if (mp[j].find(h[i])!=mp[j].end()) {
				pos=mp[j][h[i]];
				if (pos<=r) ans=min(ans, pos-j+1);
			}
			printf("%d\n", ans);
		}
	}
}

namespace task{
	multiset<int> s;
	vector<pair<int, int>> que[N];
	int nxt[N], ans[N], pos[N], top;
	pair<int, int> sta[N], suf[21][N];
	void solve() {
		for (int i=1,l,r; i<=q; ++i) {
			l=read(); r=read();
			que[l].pb({r, i});
		}
		for (int i=1; i<=lim; ++i) pos[i]=n+1, s.insert(n+1);
		
		for (int i=n; i; --i) {
			s.erase(s.find(pos[a[i]])); s.insert(i);
			nxt[i]=pos[a[i]], pos[a[i]]=i;
			while (top && sta[top].fir<=nxt[i]) --top;
			sta[++top]={nxt[i], i};
			for (auto& it:que[i]) {
				int val=(*--s.upper_bound(it.fir));
				ans[it.sec]=val-i+1;
				// cout<<"sta: "; for (int i=top; i; --i) cout<<"("<<sta[i].fir<<','<<sta[i].sec<<") "; cout<<endl;
				// for (int j=i; j<it.fir; ++j) {
				// 	val=max(val, nxt[j]);
				// 	if (val>it.fir) break;
				// 	ans[it.sec]=min(ans[it.sec], val-j);
				// }
				for (int j=top-1; ~j; --j) {
					val=max(val, sta[j+1].fir);
					if (val>it.fir) break;
					ans[it.sec]=min(ans[it.sec], val-(sta[j].sec-1));
				}
			}
		}
		for (int i=1; i<=q; ++i) printf("%d\n", ans[i]);
	}
}

signed main()
{
	freopen("frog.in", "r", stdin);
	freopen("frog.out", "w", stdout);

	n=read();
	for (int i=1; i<=n; ++i) lim=max(lim, a[i]=read());
	q=read();
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2022-07-13 21:37  Administrator-09  阅读(2)  评论(0编辑  收藏  举报