【2021浙江省赛B/ZOJ4156】Restore Atlantis(线段树脑洞+树状树组+离线)

题目链接:https://zoj.pintia.cn/problem-sets/91827364500/problems/1384062980244979712
官方题解:https://www.zhihu.com/question/455125989/answer/1840256385

思路

对于每个 \(C \times C\) 的点,其若被矩阵覆盖的话,必然存在一个最小覆盖编号 \(min\) 和最大覆盖编号 \(max\)

那么对于每个点的 \(min\)\(max\),若在询问的区间内 \([s,t]\) 中,那么也就是说 \(s \leq min\) 并且 \(max \leq t\),那么其不会对答案产生贡献。

对于每个点,都能得到 \([min, max]\),由于题目中有多次询问,考虑离线,对查询和得到的 \([min, max]\) 区间按照 \(r\) 进行排序,扫到时将 \(min\) 对应的位置+1,查询时查询的区间内求和。看代码会更加好懂

关键在于怎么求得每个 \(C \times C\) 的点的最小覆盖编号 \(min\) 和最大覆盖编号 \(max\)

考虑从左向右扫,能够能够将线段插入/删除,一开始我用set做线段树的 node,然后华丽地TLE了,问题在于,每次查询时复杂度会多一个 \(\log n\),而题解中使用的优先队列能够使得查询复杂度为 \(O(1)\)

但是在ZOJ上跑了982ms,卡得飞起。

代码

#include <bits/stdc++.h>

#define pb push_back
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define SZ(x) (int)x.size()
#define pii pair<int, int>
#define mp make_pair

typedef long long ll;
using namespace std;

const int MAXN = 1e5 + 5;
const int MAXC = 2005;

class BIT {
public:
    int val[MAXN], n;

    inline int lowbit(int x) {
        return x & (-x);
    }

    inline void add(int pos, int v) {
        for (int i = pos; i <= n; i += lowbit(i)) val[i] += v;
    }

    inline int _query(int pos) {
        int ans = 0;
        for (int i = pos; i >= 1; i -= lowbit(i)) ans += val[i];
        return ans;
    }

    inline int query(int l, int r) {
        return _query(r) - _query(l - 1);
    }
} bit;


int minn[MAXC][MAXC], maxx[MAXC][MAXC];

class SEG {
public:
    priority_queue<int> T1[MAXN << 2], tT1[MAXN << 2];
    priority_queue<int, vector<int>, greater<int>> T2[MAXN << 2], tT2[MAXN << 2];
    
    inline void add(int rt, int L, int R, int v, int be, int en) {
        if (L <= be && en <= R) {
            T1[rt].push(v), T2[rt].push(v);
            return;
        }
        int mid = (be + en) >> 1;
        if (L <= mid) add(rt << 1, L, R, v, be, mid);
        if (R > mid) add(rt << 1 | 1, L, R, v, mid + 1, en);
    }

    inline void esc(int rt, int L, int R, int v, int be, int en) {
        if (L <= be && en <= R) {
            tT1[rt].push(v), tT2[rt].push(v);
            return;
        }
        int mid = (be + en) >> 1;
        if (L <= mid) esc(rt << 1, L, R, v, be, mid);
        if (R > mid) esc(rt << 1 | 1, L, R, v, mid + 1, en);
    }

    inline void dfs(int rt, int C, int mx, int mi, int be, int en) {
        while (!T1[rt].empty() && !tT1[rt].empty() && T1[rt].top() == tT1[rt].top()) T1[rt].pop(), tT1[rt].pop();
        while (!T2[rt].empty() && !tT2[rt].empty() && T2[rt].top() == tT2[rt].top()) T2[rt].pop(), tT2[rt].pop();
        if (!T1[rt].empty()) {
            int t1 = T1[rt].top(), t2 = T2[rt].top();
            if (t1 > mx) mx = t1;
            if (t2 < mi) mi = t2;
            // mx = max(mx, *(--T[rt].st.end())), mi = min(mi, *(T[rt].st.begin()));
        }
        if (be == en) {
            maxx[C][be] = mx, minn[C][be] = mi;
            return;
        }
        int mid = (be + en) >> 1;
        dfs(rt << 1, C, mx, mi, be, mid), dfs(rt << 1 | 1, C, mx, mi, mid + 1, en);
    }
} tree;


struct Q {
    int l, r, id;
} qs[MAXN];

struct OPS {
    int be, en, v, id;
};

vector<OPS> vec[MAXC];
vector<pii > vec2;
int res[MAXN];

int main() {
    int n, q;
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++) {
        int xa, xb, ya, yb;
        scanf("%d%d%d%d", &xa, &ya, &xb, &yb);
        vec[xa + 1].pb({ya + 1, yb, 1, i});
        vec[xb + 1].pb({ya + 1, yb, -1, i});
    }

    for (int i = 1; i <= 2000; i++) {
        for (auto &e: vec[i]) {
            if (e.v == 1) tree.add(1, e.be, e.en, e.id, 1, 2000);
            else tree.esc(1, e.be, e.en, e.id, 1, 2000);
        }
        tree.dfs(1, i, -inf, inf, 1, 2000);
    }


    int sum = 0;

    for (int i = 1; i <= 2000; i++) {
        for (int j = 1; j <= 2000; j++) {
            if (maxx[i][j] == -inf || minn[i][j] == inf) continue;
            sum++;
            vec2.pb(mp(minn[i][j], maxx[i][j]));
        }
    }

    for (int i = 1; i <= q; i++) {
        qs[i].id = i;
        scanf("%d%d", &qs[i].l, &qs[i].r);
    }

    sort(qs + 1, qs + 1 + q, [&](const Q &ta, const Q &tb) {
        if (ta.r != tb.r) return ta.r < tb.r;
        else return ta.l < tb.l;
    });


    sort(vec2.begin(), vec2.end(), [&](const pii &ta, const pii &tb) {
        return ta.second < tb.second;
    });


    bit.n = n;
    int pos = 0;
    for (int i = 1; i <= q; i++) {
        int l = qs[i].l, r = qs[i].r;
        while (pos < SZ(vec2) && vec2[pos].second <= r) {
            bit.add(vec2[pos].first, 1);
            pos++;
        }
        int idx = qs[i].id;
        res[idx] = bit.query(l, r);
    }

    for (int i = 1; i <= q; i++) printf("%d\n", sum - res[i]);

}
/*
3 6
1 1 4 4
2 2 5 5
3 3 6 6
*/

posted @ 2021-04-23 16:21  tudouuuuu  阅读(214)  评论(0编辑  收藏  举报