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 clr(int x){if(tag[x]){ds.upd(tag[x], -sm[x]); tag[x] = 0;}}
void work(int x){
    if(x >= N || !flg[x]) return;
    clr(x); 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]);
}
上一篇:《算法零基础100讲》(第1讲) 幂和对数题解


下一篇:Python布尔型