The Preliminary Contest for ICPC Asia Nanjing 2019 The beautiful values of the palace(主席树)

题意:
给定一个 n ∗ n n*n nn的螺旋矩阵,给 m m m个点,使这个矩阵里只有这 m m m个点的值是他们的值,别的值都是0。给 q q q个询问,每次给一个矩阵,求矩阵里数字之和。
思路:
求出这 m m m个点的值,然后对 y y y坐标离散化,然后对 x x x从小到大排序,按 x x x的大小插入主席树,主席树记录的是前缀和,由于主席树每个节点都是一颗线段树,所以可以在查询区间大小时,只要查询离散化后的 l x lx lx r x rx rx间的线段树 l y ly ly r y ry ry的区间和就是答案了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
int t, n, m, p, root[N], cnt;
int x1, x2, yz1, yz2;
vector<int> vx, vy;
struct nod {
    int x, y, w;
    bool operator<(const nod &a)const {
        return x < a.x;
    }
} no[N];
struct node {
    int l, r;
    ll sum;
} zxs[N * 40];
ll getn(ll x, ll y) {
    ll qs = n / 2, q = min(n - y + 1, min(n - x + 1, min(x, y))) - 1;
    if (x == qs + 1 && y == qs + 1)
        return n * n;
    ll ans = 1ll * q * (8 * qs + 8 * (qs - q + 1)) / 2;
    if (n - x == q)
        ans += n - q - y + 1;
    else if (y - 1 == q)
        ans += n - 2 * q + 1 + n - q - 1 - x;
    else if (x - 1 == q)
        ans += n - 2 * q + 1 + n - 2 * q - 2 + y - q - 1;
    else
        ans += n - 2 * q + 1 + n - 2 * q - 2 + n - 2 * q - 1 + x - q - 1;
    return ans;
}
ll cal(ll x) {
    ll sum = 0;
    while (x)
        sum += x % 10, x /= 10;
    return sum;
}
void add(int l, int r, int pre, int &now, int pos, ll num) {
    zxs[++cnt] = zxs[pre], now = cnt, zxs[cnt].sum += num;
    if(l == r)
        return;
    int m = (l + r) >> 1;
    if(pos <= m)
        add(l, m, zxs[pre].l, zxs[now].l, pos, num);
    else
        add(m + 1, r, zxs[pre].r, zxs[now].r, pos, num);
}
ll query(int pl, int pr, int l, int r, int L, int R) {
    if(pl <= l && r <= pr)
        return zxs[R].sum - zxs[L].sum;
    ll m = (l + r) >> 1, ans = 0;
    if(pl <= m)
        ans += query(pl, pr, l, m, zxs[L].l, zxs[R].l);
    if(pr > m)
        ans += query(pl, pr, m + 1, r, zxs[L].r, zxs[R].r);
    return ans;
}
int main() {
    scanf("%d", &t);
    while(t--) {
        cnt = 0;
        memset(root, 0, sizeof root);
        scanf("%d%d%d", &n, &m, &p);
        vx.clear(), vy.clear();
        for(int i = 1; i <= m; i++) {
            scanf("%d%d", &no[i].x, &no[i].y);
            no[i].w = cal(getn(no[i].x, no[i].y));
            vx.push_back(no[i].x), vy.push_back(no[i].y);
        }
        sort(no + 1, no + m + 1);
        sort(vx.begin(), vx.end());//vx不能erase,因为下面二分查询的是vx的位置,erase后位置少了就不准了。
        sort(vy.begin(), vy.end()), vy.erase(unique(vy.begin(), vy.end()), vy.end());
        int sz = vy.size();
        for(int i = 1; i <= m; i++) {
            int ny = lower_bound(vy.begin(), vy.end(), no[i].y) - vy.begin() + 1;
            add(1, sz, root[i - 1], root[i], ny, no[i].w);
        }
        while(p--) {
            //由于y坐标离散化的是他们的值,所以相同值离散化后是一样的
            scanf("%d%d%d%d", &x1, &yz1, &x2, &yz2);//下面二分的是位置,lx,ly要用lower_bound计算离散化后的位置
            int lx = lower_bound(vx.begin(), vx.end(), x1) - vx.begin() + 1;
            int ly = lower_bound(vy.begin(), vy.end(), yz1) - vy.begin() + 1;
            //这里用upper_bound是为了查找下一个位置,防止和lx相同
            int rx = upper_bound(vx.begin(), vx.end(), x2) - vx.begin();
            //这里的upper_bound也是查找下一个位置,和x一样,但不能用
            //lower_bound(vy.begin(), vy.end(), no[i].y) - vy.begin() + 1;
            //因为如果这样的话,当yz2恰好是一个没有点在上面的坐标,所以要找离它最近的而且比它小的坐标,
            //若比它大,则多计算了就
            int ry = upper_bound(vy.begin(), vy.end(), yz2) - vy.begin();
            printf("%lld\n", query(ly, ry, 1, sz, root[lx - 1], root[rx]));
        }
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值