The beautiful values of the palace - 园丁的花园 - CDQ分治 - 二维偏序 + 螺旋矩阵

给出n * n的矩阵,矩阵里有一些点存在值,现在有q个查询,查询某些矩阵里值的和
把每次查询拆成前缀和的形式,那么利用二维偏序,对每一个查询求出比自己坐标小的值的和
传送门
园丁的花园就是这个模板,然后在此基础上加了一个螺旋矩阵,
传送门可以O(1)查询某个点的数值

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1e6 + 5;
struct Query{
    int x, y;
    ll op;
    int id;
    bool operator < (const Query &b) const {
        return x == b.x ? (y == b.y ? op : y < b.y) : x < b.x;
    }
} q[N], tmp[N];
int tot = 0;
ll ans[N];
void cdq(int l, int r){
    if(l == r) return;
    int mid = (l + r) >> 1;
    cdq(l, mid); cdq(mid + 1, r);
    int posa = l, posb = mid + 1, pos = l;
    ll tot = 0;
    while(posa <= mid && posb <= r) {
        if(q[posa].y <= q[posb].y) tot += q[posa].op, tmp[pos++] = q[posa++];
        else ans[q[posb].id] += tot, tmp[pos++] = q[posb++];
    }
    while(posa <= mid) tmp[pos++] = q[posa++];
    while(posb <= r) ans[q[posb].id] += tot, tmp[pos++] = q[posb++];
    for(int i = l; i <= r; i++) q[i] = tmp[i];
}
ll num(ll n, ll i, ll j){ // 螺旋矩阵O(1)查询
    i = n - i + 1, j = n - j + 1;
    ll ans = 0;
    ll minn = min(i, min(j, min(n - i + 1, n - j + 1)));
    if(i <= j) ans = minn * (4 * (n - 1) - 4 * minn) + 10 * minn - 4 * n - 3 + i + j;
    else ans = minn * (4 * n - 4 * minn) + 2 * minn + 1 - i - j;
    ll tot = 0;
    while(ans) { tot += ans % 10; ans /= 10; }
    return tot;
}
void solve(){
    memset(ans, 0, sizeof(ans));
    tot = 0;
    int n, m, qq;
    scanf("%d%d%d", &n, &m, &qq);
    for(int i = 1, x, y; i <= m; i++) {
        scanf("%d%d", &x, &y);
        q[++tot] = Query{x, y, num(n, x, y), 0};
    }
    int ans_tot = 0;
    for(int i = 1, x1, y1, x2, y2; i <= qq; i++) {
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        q[++tot] = Query{x2, y2, 0, ++ans_tot};
        q[++tot] = Query{x1 - 1, y2, 0, ++ans_tot};
        q[++tot] = Query{x2, y1 - 1, 0, ++ans_tot};
        q[++tot] = Query{x1 - 1, y1 - 1, 0, ++ans_tot};
    }
    sort(q + 1, q + tot + 1);
    cdq(1, tot);
    for(int i = 1; i + 3 <= ans_tot; i += 4) {
        printf("%lld\n", ans[i] - ans[i + 1] - ans[i + 2] + ans[i + 3]);
    }
}
int main(){
    int t; cin >> t;
    while(t--) solve();
    return 0;
}
posted @ 2020-08-30 20:59  Emcikem  阅读(132)  评论(0编辑  收藏  举报