[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;
}
posted @ 2022-08-05 15:40  stff577  阅读(131)  评论(0编辑  收藏  举报