[2021 ICPC 台北 C] Community Service
https://codeforces.com/gym/103443/problem/C
题意:
每次添加一条线段,或者询问与该区间有交的线段中最后一条被放入的线段,并删除该线段。
思路:
朴素地想一下, 相当于每次询问区间最值,然后将最值覆盖的区间还原到添加该最值前的状态,然后再把到现在的值再覆盖一遍。
我们考虑一下如何将影响只限制在需要修改的最值区间里。因为区间和线段有交就可以,所以线段突出来的部分(即不在询问区间里的部分)可能是在中间插入的。要删除中间的一个值,考虑用链表来维护。删除的时候需要看一下,如果在链表尾部,则需要更新一下最大值。一段区间在线段树上被分成 \(O(logn)\) 段,所以对链表进行删除操作的时候总时间复杂度也是 \(O(logn)\) 的。线段树上并不需要将链表 \(pushdown\) 下去, \(up\) 的时候操作下就行。时间复杂度 \(O(mlogn)\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 7;
int cntLk;
struct Link {
int pre, suf;
int val;
void init(int v) {
pre = suf = -1;
val = v;
}
}lk[N << 2];
int del(int k) {
int rear = -2;
if (lk[k].suf == -1) rear = lk[k].pre;
else lk[ lk[k].suf ].pre = lk[k].pre;
if (lk[k].pre != -1) lk[ lk[k].pre ].suf = lk[k].suf;
return rear;
}
int ins(int k, int v) {
++cntLk;
lk[cntLk].init(v);
if (k != -1) {
lk[k].suf = cntLk;
lk[cntLk].pre = k;
}
return cntLk;
}
vector<int> G[N];
struct Seg {
#define ls (id << 1)
#define rs (id << 1 | 1)
#define mid ((l + r) >> 1)
int t[N << 2], mx[N << 2];
void init() {
memset(t, -1, sizeof(t));
}
void cover(int id, int l, int r, int ql, int qr, int v) {
if (l > qr || r < ql) return;
if (l >= ql && r <= qr) {
t[id] = ins(t[id], v);
mx[id] = v;
G[v].emplace_back(t[id]);
return;
}
cover(ls, l, mid, ql, qr, v);
cover(rs, mid + 1, r, ql, qr, v);
mx[id] = max(mx[ls], mx[rs]);
}
int query(int id, int l, int r, int ql, int qr) {
if (l > qr || r < ql) return 0;
if (l >= ql && r <= qr) return mx[id];
return max({t[id] != -1? lk[ t[id] ].val : 0, query(ls, l, mid, ql, qr), query(rs, mid + 1, r, ql, qr)});
}
void modify(int id, int l, int r, int ql, int qr, int v) {
if (l > qr || r < ql) return;
if (l >= ql && r <= qr) {
int now = del(G[v].back());
G[v].pop_back();
if (now != -2) t[id] = now;
if (t[id] == -1) mx[id] = 0;
else mx[id] = lk[ t[id] ].val;
if (l != r) mx[id] = max({mx[id], mx[ls], mx[rs]});
return;
}
modify(ls, l, mid, ql, qr, v);
modify(rs, mid + 1, r, ql, qr, v);
mx[id] = max({t[id] != -1? lk[ t[id] ].val : 0, mx[ls], mx[rs]});
}
}seg;
map<int, string> mp;
int L[N], R[N];
void solve() {
int n, m;
cin >> n >> m;
n--;
seg.init();
int op, l, r;
string s;
int cnt = 0;
for (int i = 1; i <= m; ++i) {
cin >> op;
if (op == 1) {
cin >> s >> l >> r;
++cnt;
L[cnt] = l;
R[cnt] = r;
mp[cnt] = s;
seg.cover(1, 0, n, l, r, cnt);
reverse(G[cnt].begin(), G[cnt].end());
} else {
cin >> l >> r;
int mx = seg.query(1, 0, n, l, r);
if (mx == 0) {
cout << ">_<" << '\n';
} else {
cout << mp[mx] << '\n';
seg.modify(1, 0, n, L[mx], R[mx], mx);
}
}
}
}
int main() {
#ifndef stff577
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cout << fixed << setprecision(20);
#endif
int t = 1;
while (t--) solve();
return 0;
}