The Preliminary Contest for ICPC Asia Nanjing 2019 A. The beautiful values of the palace(离散化、树状数组)

https://nanti.jisuanke.com/t/41298

Here is a square matrix of n∗nn * nnn, each lattice has its value (nnn must be odd), and the center value is n∗nn * nnn. Its spiral decline along the center of the square matrix (the way of spiral decline is shown in the following figure:)

The grid in the lower left corner is (1,1) and the grid in the upper right corner is (n , n)

Now I can choose mmm squares to build palaces, The beauty of each palace is equal to the digital sum of the value of the land which it is located. Such as (the land value is 123213123213123213,the beautiful values of the palace located on it is 1+2+3+2+1+3=121+2+3+2+1+3=121+2+3+2+1+3=12) (666666666 -> 181818) (456456456 ->151515)

Next, we ask ppp times to the sum of the beautiful values of the palace in the matrix where the lower left grid(x1,y1x_1,y_1x1,y1), the upper right square (x2,y2x_2,y_2x2,y2).

Input

The first line has only one number TTT .Representing TTT-group of test data (T≤5)(T\le 5)(T5)

The next line is three number: n m pn \ m \ pn m p

The mmm lines follow, each line contains two integers the square of the palace (x,y)(x, y )(x,y)

The ppp lines follow, each line contains four integers : the lower left grid (x1,y1)(x_1,y_1)(x1,y1) the upper right square (x2,y2)(x_2,y_2)(x2,y2)

Output

Next, p1+p2...+pTp_1+p_2...+p_Tp1+p2...+pT lines: Represent the answer in turn(n≤106)(m,p≤105)(n \le 10^6)(m , p \le 10^5)(n106)(m,p105)



Solution

本题一个思维点 通过 X,Y 的坐标求出相应数字,可以通过分类讨论,或者推公式找出结论 地图大小为 一定为奇数
;; //确定该点在第几圈螺旋//在向右与向上的路线上 //在向左与向下的路线上
对于这个题而言
就转化为求任意子矩阵之和
离散化 宫殿和询问的y坐标 对于每个询问要拆成4次询问 代表 , 这点为左下节点 , 为右上节点所求得矩阵和 对于查询
; 因此一次询问就可以看出求求四次二维前缀和 标记每次询问是加还是减; 将宫殿和询问按 坐标排序
维护一个带修树状数组
ans = map[x2][y2]− map[x2][y1−1]− map[x1−1][y2]+ map[x1−1][y1−1]
每加入一个宫殿添加其值
每加入个询问就求其前缀和

相当于第一维靠排序后离线处理,第二维靠树状数组

AC Code

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
ll n, m, q;
int const maxn = 1000005;

class TreeArray {
    public:
        long long treeArray[maxn]{};

        inline int lowBit(int x) {
            return x & (-x);
        }

        void add(int treeIndex, int value) {
            while (treeIndex <= maxn) {
                treeArray[treeIndex] += value;
                treeIndex += lowBit(treeIndex);
            }
        }

        long long sum(int x) {
            long long ans = 0;
            while (x != 0) {
                ans += treeArray[x];
                x -= lowBit(x);
            }
            return ans;
        }

        long long query(int l, int r) {
            if (l > r) {
                return 0;
            }
            return sum(r) - sum(l - 1);
        }

        void clear() {
            memset(treeArray, 0, sizeof(treeArray));
        }
};

ll calculate(int x, int y) {
    ll xx = x - n / 2 - 1; //确定该点在第几圈螺旋
    ll yy = y - n / 2 - 1;
    ll t = max(abs(xx), abs(yy));
    if (xx >= yy)
        return (ll) n * n - 4 * t * t - 2 * t - xx - yy;    //在向右与向上的路线上
    else return (ll) n * n - 4 * t * t + 2 * t + xx + yy;   //在向左与向下的路线上
}

int resolve(ll value) {
    int res = 0;
    while (value) {
        res += value % 10;
        value /= 10;
    }
    return res;
}

class Point {
    public:
        int x, y, type, id;

        explicit Point(int x = 0, int y = 0, int type = 0) : x(x), y(y), type(type), id(0) {}

        bool operator<(const Point &rhs) const {
            if (x == rhs.x) {
                if (y == rhs.y)
                    return type < rhs.type;
                return y < rhs.y;
            } else return x < rhs.x;
        }
};

class Query {
    public:
        int x1, y1, x2, y2;

        explicit Query(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0) : x1(x1), y1(y1), x2(x2), y2(y2) {}
};

vector<Point> points;
vector<Query> queries;
vector<int> ys;
TreeArray treeArray;
map<int, map<int, ll> > matrix;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    for (cin >> t; t--;) {
        matrix.clear();
        points.clear();
        queries.clear();
        ys.clear();
        treeArray.clear();
        cin >> n >> m >> q;
        for (int i = 0; i < m; ++i) {
            int x, y;
            cin >> x >> y;
            points.emplace_back(x, y, 0);
            ys.push_back(y);
        }
        for (int i = 0; i < q; ++i) {
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            ys.push_back(y1 - 1);
            ys.push_back(y2);
            queries.emplace_back(x1, y1, x2, y2);
            points.emplace_back(x2, y2, 1);
            points.emplace_back(x1 - 1, y1 - 1, 1);
            points.emplace_back(x1 - 1, y2, 1);
            points.emplace_back(x2, y1 - 1, 1);
        }
        sort(points.begin(), points.end());
        sort(ys.begin(), ys.end());
        ys.erase(unique(ys.begin(), ys.end()), ys.end());
        for (auto &point : points)
            point.id = lower_bound(ys.begin(), ys.end(), point.y) - ys.begin() + 1;
        for (auto &point: points) {
//            cout << "point.id: " << point.id << "  " << point.type << endl;
            if (point.type == 0)
                treeArray.add(point.id, resolve(calculate(point.x, point.y)))/*,
                        cout << "add " << point.id << " : " << resolve(calculate(point.x, point.y)) << endl*/;
            else
                matrix[point.x][point.y] = treeArray.sum(point.id)/*, cout << "sum( " << point.id << ") : matrix ["
                                                                         << point.x << ", " << point.y << "] "
                                                                         << matrix[point.x][point.y] << endl*/;
        }
        for (auto &query:queries) {
            int x1 = query.x1, y1 = query.y1, x2 = query.x2, y2 = query.y2;
//            cout << matrix[x2][y2] << " " << matrix[x1 - 1][y1 - 1] << " " << matrix[x1 - 1][y2] << " "
//                 << matrix[x2][y1 - 1] << endl;
            cout << matrix[x2][y2] + matrix[x1 - 1][y1 - 1] - matrix[x1 - 1][y2] - matrix[x2][y1 - 1] << "\n";
        }
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值