• LG6783 [Ynoi2008] rrusq【扫描线,KDT】


    给定二维平面上 \(n\) 个关键点,\(m\) 个矩形,每个关键点有权值 \(a_i\)

    \(q\) 次询问 \(l,r\),求编号在 \([l,r]\) 内的矩形的并包含的关键点的权值和。

    \(n,m\le 10^5\)\(q\le 10^6\)\(a_i\le 10^4\)


    对询问左端点扫描线,从大到小枚举 \(l\) 时维护对应右端点的答案。

    要对每个点维护包含其的矩形的编号最小值,加到对应的数组上,于是对点建 KDT,维护子树权值和,插入一个矩形时遍历 KDT 上的点然后打标记,同时把子树的标记收回(对每个点维护子树内有无标记即可)。

    现在需要对数组 \(O(m\sqrt n)\) 次单点修改,\(O(q)\) 次查询前缀和,分块即可,时间复杂度 \(O(n\log n+m\sqrt n+q\sqrt m)\)

    #include<bits/stdc++.h>
    #define PB push_back
    using namespace std;
    const int N = 1 << 20;
    template<typename T>
    bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
    template<typename T>
    bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
    struct DS {
        int len, num, bl[N], val[N], sm[1003], rg[1003];
        void init(int n){
            len = sqrt(n);
            for(int i = 1;i <= n;++ i) bl[i] = (i-1) / len + 1;
            num = bl[n];
            for(int i = 1;i <= num;++ i) rg[i] = min(n, i * len);
        }
        void upd(int p, int v){val[p] += v; sm[bl[p]] += v;}
        int qry(int p){
            int res = 0;
            for(int i = p;i > rg[bl[p]-1];-- i) res += val[i];
            for(int i = bl[p]-1;i;-- i) res += sm[i];
            return res;
        }
    } ds;
    int n, m, q, qr[N], ans[N], p[N], id[N], val[N], xl[N], xr[N], yl[N], yr[N];
    vector<int> G[100003];
    int sm[N], mnx[N], mxx[N], mny[N], mxy[N], tag[N];
    bool flg[N];
    void build(int x, int L, int R, bool o){
        if(L == R){
            sm[x] = val[id[L]];
            mnx[x] = mxx[x] = id[L];
            mny[x] = mxy[x] = p[id[L]];
            return;
        }
        int md = L+R>>1;
        if(o) nth_element(id+L, id+md, id+R+1);
        else nth_element(id+L, id+md, id+R+1, [&](int x, int y){return p[x] < p[y];});
        build(x<<1, L, md, !o);
        build(x<<1|1, md+1, R, !o);
        mnx[x] = min(mnx[x<<1], mnx[x<<1|1]);
        mny[x] = min(mny[x<<1], mny[x<<1|1]);
        mxx[x] = max(mxx[x<<1], mxx[x<<1|1]);
        mxy[x] = max(mxy[x<<1], mxy[x<<1|1]);
        sm[x] = sm[x<<1] + sm[x<<1|1];
    }
    int xL, xR, yL, yR, now;
    void work(int x){
        if(x >= N || !flg[x]) return;
        if(tag[x]){ds.upd(tag[x], -sm[x]); tag[x] = 0;}
        work(x<<1); work(x<<1|1); flg[x] = false;
    }
    void pdown(int x){
        if(tag[x]){
            tag[x<<1] = tag[x<<1|1] = tag[x];
            flg[x<<1] = flg[x<<1|1] = true; tag[x] = 0;
        }
    }
    void upd(int x){
        if(x >= N || xL > mxx[x] || xR < mnx[x] || yL > mxy[x] || yR < mny[x]) return;
        if(xL <= mnx[x] && mxx[x] <= xR && yL <= mny[x] && mxy[x] <= yR){
            work(x); ds.upd(tag[x] = now, sm[x]);
        } else {
            pdown(x); upd(x<<1); upd(x<<1|1);
        }
        flg[x] = true;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin >> n;
        for(int i = 1;i <= n;++ i){cin >> p[i] >> val[i]; id[i] = i;}
        cin >> m; ds.init(m);
        for(int i = 1;i <= m;++ i) cin >> xl[i] >> xr[i] >> yl[i] >> yr[i];
        cin >> q;
        for(int i = 1, j;i <= q;++ i){cin >> j >> qr[i]; G[j].PB(i);}
        build(1, 1, n, false);
        for(int i = m;i;-- i){
            now = i; xL = xl[i]; xR = xr[i]; yL = yl[i]; yR = yr[i]; upd(1);
            for(int j : G[i]) ans[j] = ds.qry(qr[j]);
        }
        for(int i = 1;i <= q;++ i) printf("%d\n", ans[i]);
    }
    
  • 相关阅读:
    js事件分类
    过3s弹出广告条,点叉号关闭
    js进阶
    js入门
    html
    R Markdown + Infinite Moon Reader + 编辑实时更新
    png转ico+windows图标+GIMP
    微生物+计算细胞倍增时间
    使用Mathjax网页插入公式
    Firefox+zoom+全局缩放比例
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/15699797.html
Copyright © 2020-2023  润新知