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]);
}
标签:Ynoi2008,return,val,int,sqrt,bool,扫描线,KDT,id 来源: https://www.cnblogs.com/AThousandMoons/p/15699797.html