https://codeforces.com/gym/103260/problem/H
写了一坨答辩代码,已经神志不清了,后面再补上思路吧,先给上题解的描述还有草稿纸上一些图。
简而言之,学会了一种套路,求一些线段中选出不被任何一个线段完全覆盖的所有线段,支持删除线段操作。
#include
using namespace std;
#define MAXN 500005
int n, q;
int a[MAXN];
pair<pair<int, int>, int> Q[MAXN];
#define LX (x<<1)
#define RX ((x<<1)|1)
struct segment_tree {
struct node {
int l, r;
int v; // 区间最大值
int num; // 区间线段个数
int tag; // 区间加标记
} a[MAXN*8];
void merge(int x) {
if (a[x].l == a[x].r) return;
a[x].num = a[LX].num + a[RX].num;
a[x].v = max(a[LX].v, a[RX].v);
}
void build(int x, int l, int r) {
a[x].l = l;
a[x].r = r;
a[x].num = a[x].tag = 0;
a[x].v = -1;
if (l == r) return;
build(LX, l, (l+r)/2);
build(RX, (l+r)/2+1, r);
merge(x);
}
void down_tag(int x) {
if (a[x].l == a[x].r) return;
if (a[LX].num) a[LX].v += a[x].tag, a[LX].tag += a[x].tag;
if (a[RX].num) a[RX].v += a[x].tag, a[RX].tag += a[x].tag;
a[x].tag = 0;
}
void set(int x, int pos, int v) { // 将线段 pos 处的值设置为 v,若 v==-1 则说明清除这个点
if (a[x].l == a[x].r) {
a[x].v = v;
a[x].num = (v>=0);
return;
}
down_tag(x);
if (a[LX].r >= pos) set(LX, pos, v);
else set(RX, pos, v);
merge(x);
}
void add(int x, int L, int R, int d) { // 给区间内存在的线段 +d
if (!a[x].num) return;
if (L<=a[x].l && a[x].r<=R) {
a[x].tag += d;
a[x].v += d;
return;
}
down_tag(x);
if (a[LX].r>=L) add(LX, L, R, d);
if (a[RX].l<=R) add(RX, L, R, d);
merge(x);
}
int query(int x, int pos) { // 查询 pos 处的值
if (a[x].l == a[x].r) {
return a[x].v;
}
down_tag(x);
if (a[LX].r >= pos) return query(LX, pos);
return query(RX, pos);
}
int mxv(int x) { // 查询整个线段的最大值,若线段为空则返回-1
return a[x].num ? a[x].v : -1;
}
int id_mxv(int x) { // 返回最大值所在的下标(左端点)(有多个则随便一个)
if (a[x].l == a[x].r) {
return a[x].l;
}
down_tag(x);
return (a[LX].v == a[x].v) ? id_mxv(LX) : id_mxv(RX);
}
} A;
struct segment_tree1 {
struct node {
int l, r;
pair<int, int> v; //
} a[MAXN*8];
void build(int x, int l, int r) {
a[x].l = l;
a[x].r = r;
if (l == r) return;
build(LX, l, (l+r)/2);
build(RX, (l+r)/2+1, r);
}
void set(int x, int pos, pair<int, int> v) {
if (a[x].l == a[x].r) {
a[x].v = v;
return;
}
if (a[LX].r >= pos) set(LX, pos, v);
else set(RX, pos, v);
a[x].v = (a[RX].v.first > a[LX].v.first) ? a[RX].v : a[LX].v; // maxr 相同,取左边的
}
pair<int, int> query(int x, int L, int R) {
if (L<=a[x].l && a[x].r<=R) {
return a[x].v;
}
pair<int, int> lv, rv;
if (a[LX].r >= L) lv = query(LX, L, R);
if (a[RX].l <= R) rv = query(RX, L, R);
return (rv.first>lv.first) ? rv : lv;
}
} B;
struct BIT {
int c[MAXN];
int lowbit(int x) {return x&(-x);}
void add(int x, int v) {
for (; x<=n; x+=lowbit(x)) c[x]+=v;
}
int query(int x) {
int ret=0;
for (; x>0; x-=lowbit(x)) ret+=c[x];
return ret;
}
int query(int l, int r) {
return query(r)-query(l-1);
}
} C;
vector<int> pos_val[MAXN]; // pos_val[v] = {i | a[i]==v}
vector<int> qid_l[MAXN];
int active_qid_l[MAXN];
int ans[MAXN];
set<pair<int, int>> active_l; //
set<pair<int, int>> active_r; //
void add_qseg(int ql) {
int qid = qid_l[ql].back();
int qr = Q[qid].first.second;
active_l.insert({ql, qid});
active_r.insert({qr, qid});
active_qid_l[ql] = qid;
int tmp = C.query(ql, qr);
A.set(1, ql, tmp);
qid_l[ql].pop_back();
if (qid_l[ql].size()) {
B.set(1, ql, {Q[qid_l[ql].back()].first.second, qid_l[ql].back()});
}
else {
B.set(1, ql, {0, 0});
}
}
void del_qseg(int ql) {
int qid = active_qid_l[ql];
int qr = Q[qid].first.second;
active_l.erase({ql, qid});
active_r.erase({qr, qid});
A.set(1, ql, -1);
}
void activate_qseg(int tmpl, int tmpr, int minr) {
while (tmpr>=tmpl) {
auto [_, qid] = B.query(1, tmpl, tmpr);
if (!qid || Q[qid].first.second < minr) break;
add_qseg(Q[qid].first.first);
tmpr = Q[qid].first.first-1;
}
}
void solve()
{
scanf("%d%d", &n, &q);
for (int i=1; i<=n; i++) {
scanf("%d", &a[i]);
pos_val[a[i]].push_back(i);
}
for (int i=1; i<=q; i++) {
Q[i].second = i;
scanf("%d%d", &Q[i].first.first, &Q[i].first.second);
}
A.build(1, 1, n);
B.build(1, 1, n);
for (int i=1; i<=n; i++) C.add(i, 1);
sort(Q+1, Q+q+1);
for (int i=1; i<=q; i++) qid_l[Q[i].first.first].push_back(i);
for (int i=1; i<=q; i++) if (Q[i].first.first != Q[i-1].first.first) {
int ql = Q[i].first.first;
int qid = qid_l[ql].back();
int qr = Q[qid].first.second;
B.set(1, ql, {qr, qid});
}
activate_qseg(1, n, 0);
for (int x=n; x>=0; x--) {
for (int pos: pos_val[x]) {
auto p_l = active_r.lower_bound({pos, 0});
auto p_r = active_l.upper_bound({pos, n});
int L=n+1, R=0;
if (p_l != active_r.end()) {
L = Q[p_l->second].first.first;
}
if (p_r != active_l.begin()) {
p_r--;
R = p_r->first;
}
if (L <= R) {
A.add(1, L, R, -1);
}
C.add(pos, -1);
}
while (A.mxv(1) >= x) {
int cur_l = A.id_mxv(1);
int cur_id = active_qid_l[cur_l];
int cur_r = Q[cur_id].first.second;
ans[Q[cur_id].second] = x;
int tmpl = cur_l, tmpr = cur_r, minr = 0;
auto p_nxt = ++active_l.find({cur_l, cur_id});
if (p_nxt != active_l.end()) {
tmpr = min(tmpr, Q[p_nxt->second].first.first - 1);
}
auto p_lst = active_r.find({cur_r, cur_id});
if (p_lst != active_r.begin()) {
p_lst--;
minr = Q[p_lst->second].first.second + 1;
}
del_qseg(cur_l);
activate_qseg(tmpl, tmpr, minr);
}
}
for (int i=1; i<=q; i++) {
printf("%d\n", ans[i]);
}
}
int main()
{
solve();
}