[Ynoi2008] rrusq

直接做感觉不太行,考虑对于询问 \((l, r)\) 直接扫描线。

将询问 \((l, r)\) 挂在端点 \(l\) 上,然后从大到小加入矩阵 \(l\)

然后去看 \(n\) 个点中哪些能够被覆盖,记录 \(p_i\) 表示点 \(i\) 被最前面的 \(id\) 矩形覆盖,然后对于询问,就只需要查询所有 \(l \leq p_i \leq r\)\(a_i\) 之和就行了。

然后由于是从后往前扫的,所以前面的限制可以去掉,因为不会出现比 \(l\) 更前面的矩形,于是只需要找 \(p_i \leq r\)\(a_i\) 之和就好。

那么对于每个点 \(i\) 直接在 \(p_i\) 位置加 \(a_i\) 然后求区间和就好了,这个不难,问题在于加入矩形。

加入矩形的时候,要去寻找二维平面中哪些点被包含,直接建立一个 kdtree,注意到这里建立 kdtree 采用 leafy 结构构建,方便打下船标记。

然后直接在 kdtree 上爆搜出所有在自己范围内的节点,然后对应的直接进行区间覆盖,然后每次找到一个子树符合要求,记录这个子树中的 \(\sum a_i\),然后直接先暴力清空子树内有过标记的点,消除它们的影响,然后在对应的重新加入现在这个子树对当前加入矩形 \(i\) 的贡献 \(\sum a_i\) 即可。

复杂度证明考虑,每种标记 \(i\) 只会被打一次和删除一次,于是复杂度等价于 kdtree 矩形查找的复杂度,也就是 \(\sqrt{n}\)

这样做区间和就不太能直接树状数组,考虑根号平衡一下,用个 \(O(1)\) 改,\(O(\sqrt{n})\) 查的分块来维护这个序列和就好了。

这样复杂度就为 \(O(m \sqrt{n} + q\sqrt{n})\),因为常数小的原因,跑的很快,反正能过、

追求理论复杂度的话可以写个多叉树,不过因为常数原因真的不一定很快,因为 kdtree 常数大。

(打脸了,贼快。

// 德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱
// 德丽莎的可爱在于德丽莎很可爱,德丽莎为什么很可爱呢,这是因为德丽莎很可爱!
// 没有力量的理想是戏言,没有理想的力量是空虚
#include <bits/stdc++.h>
#define LL long long
using namespace std;
char ibuf[1 << 15], *p1, *p2;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1 << 15, stdin), p1==p2) ? EOF : *p1++)
inline int read() {
  char ch = getchar();  int x = 0, f = 1;
  while (ch < '0' || ch > '9')  {  if (ch == '-')  f = -1;  ch = getchar();  }
  while (ch >= '0' && ch <= '9')  x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
  return x * f;
}
void print(LL x) {
  if (x > 9)  print(x / 10);
  putchar(x % 10 + '0');
}
template<class T> bool chkmin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool chkmax(T &a, T b) { return a < b ? (a = b, true) : false; }
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define repd(i, l, r) for (int i = (l); i >= (r); i--)
#define REP(i, l, r)  for (int i = (l); i < (r); i++)
bool o1;
const int N = 6e5, M = 1e6 + 114514;
int n, m, q, a[N];
LL Ans[M];
struct blocks {
  int pos[N], siz, bel, L[N], R[N];
  LL sum[N], tag[N];
  void init(int n) {
    siz = sqrt(n);
    bel = (n - 1) / siz + 1;
    rep (i, 1, bel) {
      L[i] = (i - 1) * siz + 1;
      R[i] = min(i * siz, n);
      rep (j, L[i], R[i])  pos[j] = i;
    }
  }
  void add(int x,int val) {
    // cout << x << " " << val << " qwqwqq\n";
    sum[x] += val;
    tag[pos[x]] += val;
  }
  LL ask(int x) {
    if (x > m)  return 0;
    LL ans = 0;
    rep (i, pos[x] + 1, bel)  ans += tag[i];
    rep (i, x, R[pos[x]])  ans += sum[i];
    return ans;
  }
} blk;
struct node {  int x, y, id;  } po[N];
int ls(int p) {  return p << 1;  }
int rs(int p) {  return p << 1 | 1; }
int cmpx(node x, node y) {  return x.x < y.x;  }
int cmpy(node x,node y) {  return x.y < y.y;  }
struct kdtree {  int lx, rx, ly, ry; LL sum;  }  s[N], h[N];
kdtree merge(kdtree a, kdtree b) {
  kdtree c;
  c.lx = min(a.lx, b.lx);
  c.ly = min(a.ly, b.ly);
  c.rx = max(a.rx, b.rx);
  c.ry = max(a.ry, b.ry);
  c.sum = a.sum + b.sum;
  return c;
}
void build(int p,int l,int r,int d) {
  if (l == r) {
    s[p].lx = s[p].rx = po[l].x;
    s[p].ly = s[p].ry = po[l].y;
    s[p].sum = a[po[l].id];
    return;
  }
  int mid = (l + r) >> 1;
  if (d & 1)  nth_element(po + l, po + mid, po + r + 1, cmpx);
  else  nth_element(po + l, po + mid, po + r + 1, cmpy);
  build(ls(p), l, mid, (d ^ 1));
  build(rs(p), mid + 1, r, (d ^ 1));
  s[p] = merge(s[ls(p)], s[rs(p)]);
  // cout << p << " " << s[p].sum << "\n";
}
vector < pair<int,int> > G[N];
int tag[N], vis[N];
void clear(int p,int l,int r) {
  if (!vis[p])  return;
  if (tag[p]) {
    blk.add(tag[p], -s[p].sum);
    tag[p] = 0;
  }
  vis[p] = 0;
  if (l == r)  return;
  int mid = (l + r) >> 1;
  clear(ls(p),l, mid);
  clear(rs(p), mid + 1, r);
}
void pushdown(int p) {
  if (!tag[p])  return;
  tag[ls(p)] = tag[p];
  tag[rs(p)] = tag[p];
  vis[ls(p)] = 1;
  vis[rs(p)] = 1;
  tag[p] = 0;
}
void change(int p,int l,int r, kdtree qwq,int now) {
  // cout << qwq.lx << " " << qwq.rx << " " << qwq.ly <<" " << qwq.ry << "\n";
  // cout << s[p].lx << " " << s[p].rx <<" "<< s[p].ly << " "  << s[p].ry << "\n";
  // cout << "-----------\n";
  if (qwq.lx > s[p].rx || qwq.rx < s[p].lx || qwq.ly > s[p].ry || qwq.ry < s[p].ly)  return;
  if (qwq.lx <= s[p].lx && s[p].rx <= qwq.rx && qwq.ly <= s[p].ly && s[p].ry <= qwq.ry) {
    clear(p, l, r);
    tag[p] = now;
    blk.add(tag[p], s[p].sum);
    // cout << l << " " << r << " "  << tag[p] << " " << s[p].sum << "qwqwqwq\n";
  } else {
    pushdown(p);
    int mid = (l + r) >> 1;
    change(ls(p), l, mid, qwq, now);
    change(rs(p), mid + 1, r, qwq, now);
  }
  vis[p] = 1;
}
bool o2;
void solve() {
  // cout << (&o2 - &o1) * 1.0 / 1024 / 1024 << ".Mib\n";
  n = read();
  rep (i, 1, n) {
    int x = i, y = read();
    a[i] = read();
    po[i] = node{x, y, i};
  }  
  build(1, 1, n, 0);
  m = read();
  blk.init(m);
  rep (i, 1, m) {
    int x = read(), xx = read();
    int y = read(), yy = read();
    h[i].lx = x;  h[i].rx = xx;
    h[i].ly = y;  h[i].ry = yy;
  }
  q = read();
  rep (i, 1, q) {
    int l = read(), r = read();
    G[l].push_back({r, i});
  }
  repd (i, m, 1) {
    change(1, 1, n, h[i], i);
    for (auto it : G[i]) {
      Ans[it.second] = blk.ask(i) - blk.ask(it.first + 1);
    }
  }
  rep (i, 1, q)  printf("%lld\n", Ans[i]);
}
signed main () {
#ifdef LOCAL_DEFINE
  freopen("1.in", "r", stdin);
  freopen("1.ans", "w", stdout);
#endif
  int T = 1;  while (T--)  solve();
#ifdef LOCAL_DEFINE
  cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
  return 0;
}
posted @ 2022-09-28 17:14  Pitiless0514  阅读(40)  评论(1编辑  收藏  举报