1. 程式人生 > 其它 >LG6783 [Ynoi2008] rrusq【掃描線,KDT】

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]);
}