zoukankan      html  css  js  c++  java
  • 【2021浙江省赛B/ZOJ4156】Restore Atlantis(线段树脑洞+树状树组+离线)

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

    思路

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

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

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

    关键在于怎么求得每个 (C imes 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
    ", sum - res[i]);
    
    }
    /*
    3 6
    1 1 4 4
    2 2 5 5
    3 3 6 6
    */
    
    
  • 相关阅读:
    Robot Framework-资源文件的使用方法(7)
    Robot Framework-用户关键字的使用方法(6)
    robotframework 新建UI自动化测试用例实例一(2)
    robotframework--登录接口,post传递多个参数、及获取content中指定属性的值(5)
    robotframework基础知识(2)
    win7如何打开防火墙某个端口的tcp连接
    外观模式
    享元模式
    代理模式
    模板模式
  • 原文地址:https://www.cnblogs.com/tudouuuuu/p/14694426.html
Copyright © 2011-2022 走看看