LG6783 [Ynoi2008] rrusq【掃描線,KDT】
阿新 • • 發佈:2021-12-16
給定二維平面上 \(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)\)
#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]); }