window.cnblogsConfig = {//可以放多张照片,应该是在每一个博文上面的图片,如果是多张的话,那么就随机换的。 homeTopImg: [ "https://cdn.luogu.com.cn/upload/image_hosting/clcd8ydf.png", "https://cdn.luogu.com.cn/upload/image_hosting/clcd8ydf.png" ], }

CSP-S 模拟赛 Day 19

CSP-S 模拟赛 Day 19

T1

直接搞,注意判断一下两段数都不完整选上的方案数。

T2

有一个结论是,对于所有的询问,一定可以被拆成 \(O(n)\) 个四元组 \((l0,l1,r0,r1)\),保证对所有 \(l0 \le l \le l1,r0 \le r \le r1\) 这样的询问,\([l,r]\)\(mex\) 都是相同的。

支配段:对于一类长度越长,值单调递增或者递减的区间,如果要求最值,那么越短的区间肯定比较长的区间要优,所以我们要把较长的区间直接删掉,最后就剩下了 \(O(n)\) 个不交区间。我们可以直接求这个不交区间。

注意到 \(mex\) 是满足支配段所需的性质的,长度增加,\(mex\) 单调不降,所以我们就要求支配段。我们发现当区间扩张的时候,\(mex\) 变化到的值我们不好求,但是如果是收缩区间,那么 \(mex\) 要么不变,要么变成 \(a_i\)。所以考虑倒着扫描线,不难发现当 \(r \to r-1\) 时,从 \(lst_r \to r - 1\) 的区间 \(mex\) 可能变化,并且是取 \(\min\) 的,假设我们改变的区间是 \([l,r]\),并且原来的 \(mex\)\(x\),修改位置是 \(p\),所以在右端点 \([i,p]\) 之间,左端点在 \([l,r]\) 区间时,这些区间的 \(mex\) 都是 \(x\),那么我们要的支配段就是 \([r,i]\)\(mex\)\(x\)。当然 \([l,r]\) 之间在修改前可能有很多个 \(mex\),对于每一个段都要记录一次支配段。直接使用颜色段均摊。

#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
#define fir first
#define sec second
// #define memset(a, b) memset(a, b, sizeof(a))
#define memset(a, b, n) memset(a, b, sizeof(int) * (n + 5))
#define endl '\n'
using namespace std;

const int N = 1e5 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f3f3f3f3f;

int n, q;
int a[N], p[N], lst[N], ans[N];
map<int, int> mp;
struct node{
	int l, r, v;
	bool operator < (const node &rhs) const{
		return l < rhs.l;
	}
};
set<node> st;

auto split(int x){
	auto pos = st.lower_bound({x, 0, 0});
	if (pos -> l == x) return pos;
	auto [l, r, v] = *--pos;
	st.erase(pos), st.insert({l, x - 1, v});
	return st.insert({x, r, v}).fir;
}

void cover(int l, int r, int v){
	auto p1 = split(l), p2 = p1;
	while (p2 != st.end() && p2 -> v > v) p2++;
	int R;
	for (auto i = p1; i != p2; i++){
		ans[r - i->r + 1] = max(ans[r - i->r + 1], i -> v), R = i -> r;
	}
	if (p1 != p2) st.erase(p1, p2), st.insert({l, R, v});
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++) lst[i] = p[a[i]], p[a[i]] = i;
	set<int> st1;
	for (int i = 0; i <= n; i++) st1.insert(i);
	memset(p, 0, n);
	for (int i = 1; i <= n; i++) st1.erase(a[i]), p[a[i]]++;
	for (int i = 1; i <= n; i++){
		st.insert({i, i, *st1.begin()});
		p[a[i]]--;
		if (p[a[i]] == 0) st1.insert(a[i]);
	}
	for (int i = n; i >= 1; i--){
		cover(lst[i] + 1, i, a[i]);
		auto p = split(i);
		ans[1] = max(ans[1], p -> v);
		st.erase(p);
	}
	for (int i = 1; i <= n; i++) ans[i] = max(ans[i - 1], ans[i]);
	cin >> q;
	while (q--){
		int x; cin >> x;
		cout << ans[x] << endl;
	}
	return 0;
}
posted @ 2025-10-20 19:53  CCF_IOI  阅读(5)  评论(0)    收藏  举报