zoukankan      html  css  js  c++  java
  • [The Preliminary Contest for ICPC Asia Nanjing 2019] A-The beautiful values of the palace(二维偏序+思维)

    >传送门<

    前言


     这题比赛的时候觉得能做,硬是怼了一个半小时,最后还是放弃了。开始想到用二维前缀和,结果$nleq 10^{6}$时间和空间上都爆了,没有办法。赛后看题解用树状数组,一看不就是二维树状数组么,结果时间是够了,然而$sum[maxn][maxn]$空间上就爆了。于是开始研究别人的代码,终于看懂了,就觉得很神奇,这个思想很妙,后来再看别的博客,原来是二维偏序(就是利用树状数组/$CDQ$分治求$M$个点中每个点横纵坐标均小于这个点的权值和)

    题意


    有一个$nast n(nleq 10^{6})$的螺旋矩阵,图像见题目。然后有$m$个宫殿,每一个宫殿坐落在一个格子里,该宫殿的美丽值为所在格子的各个数位的和。比如一个宫殿位于值为$123$的格子,那么他的美丽值就是$1+2+3=6$。然后给你$q$个询问,每个询问包含一个矩形的左下角和右上角,要求输出在这个范围内的宫殿的美丽值的和。

    分析


     首先这题的一个思维点就在于,如何通过给你的坐标$(x,y)$快速的求出在螺旋矩阵中的相应数字。

    你可以通过分类讨论,或者找规律,推公式找出结论,要注意正是因为$n$是奇数,才有这么强的规律性。

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

    对于这个题目而言,问题就转变成了如何求任意子矩阵的和。

    假设我们用$sum[i][j]$表示以$(1,1)$为左下角,$(i,j)$为右上角所求得的矩阵和。则对于查询$x1,y1,x2,y2$就有:

          $ans = sum[x2][y2]-sum[x2][y2-1]-sum[x1-1][y1]+sum[x1-1][y1-1]$

    我们当然可以用二维树状数组求$sum[i][j]$,但是这里的$n$达到了$10^{6}$的数量级,空间上会爆掉。所以采用另外一种方法,就是二维偏序。

    就这题来说,对于某次查询的子矩阵中点$i$,都可能有另外一些点的$x,y$坐标均小于等于点$i$的$x,y$坐标,这些点的权值和即为点$i$的二维偏序值.。

    我们的做法是按照第一维排序,再用树状数组处理第二维即可。

    为什么要按照第一维排序:对于每个点,显然只有它前面的点($x$坐标小于等于该点)的权值有可能(换句话说,$x$坐标大于该点的那些点是绝对不可能被计入该点的二维偏序值的)被计入该点的二维偏序值.

    当然了,仅仅按照第一维排序是不能解决这一问题的,因为不能保证每个点前面的点的$y$坐标都小于等于这个点。

    为什么要使用树状数组:在二维偏序中,通过对每个点关于$x$坐标排序,我们得到了一个$x$轴坐标单调递增的点的序列。接下来要解决的问题,是怎么关于点$i$获取$y$坐标小于点$i$的点的数量,这时树状数组就起到作用了

    由于只有$x$坐标小于等于点$i$的点集需要被考虑(原因前面已经提到过,即只有$x$坐标小于等于点$i$的$x$坐标的点集有可能被计入点i的二维偏序值),因此我们把需要查询的$x$的值进行排序,按顺序进行查询。对于某次查询$i$,只有$x$坐标小于$i$的宫殿才能被加入树状数组,之后再用树状数组找出其中$y$坐标小于点$i$的点求和就好了。

    这里有一些细节处理,我们用$id$记录是第几次查询,用$flag$标记每次询问求前缀和是加还是减。

    Code(这里第一维按y排序)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6+10;
    int T, n, m, p, tot;
    ll c[maxn*2], ans[maxn];
    struct node {
        int x, y, id, flag;
        node(int _x = 0, int _y = 0, int _id = 0, int _flag = 0) : x(_x), y(_y), id(_id), flag(_flag) {};
        bool operator<(const node &b) const {
            return y < b.y;
        }
    }q[maxn*4];
    struct palace {
        int x, y, val;
        palace(int _x = 0, int _y = 0, int _val = 0) : x(_x), y(_y), val(_val) {};
        bool operator<(const palace &b) const {
            return y < b.y;
        }
    }a[maxn];
    
    int lowbit(int x){
        return x&-x;
    }
    void add(int x,ll val){
        if (x==0) return;
        while (x<maxn){
            c[x]+=val;
            x+=lowbit(x);
        }
    }
    ll query(int x) {
        ll ret = 0;
        while (x) {
            ret += c[x];
            x -= lowbit(x);
        }
        return ret;
    }
     
    void solve() {
        int pos = 1;
        for (int i = 1; i <= tot; i++) {
            while (pos <= m && a[pos].y <= q[i].y) {
                add(a[pos].x, a[pos].val);
                pos++;
            }
            ans[q[i].id] += query(q[i].x) * q[i].flag;
        }
    }
     
    ll sum(ll x) {
        ll ret = 0;
        while (x) {
            ret += x % 10;
            x /= 10;
        }
        return ret;
    }
    
    ll get(ll x, ll y, ll n){
        x = x-n/2-1, y = y-n/2-1;
        ll t = max(abs(x), abs(y));
        ll ans;
        if(x>=y) ans = n*n-4*t*t-2*t-x-y;
        else ans = n*n-4*t*t+2*t+x+y;
        return ans;
    }
    int main()
    {
        scanf("%d", &T);
        while (T--) {
            scanf("%d%d%d", &n, &m, &p);
            for (int i = 0; i <= 2 * n; i++) c[i] = 0;
            for (int i = 0; i <= p; i++) ans[i] = 0;
            for (int i = 1, x, y; i <= m; i++) {
                scanf("%d%d", &x, &y);
                a[i] = palace(x, y, sum(get(x, y, n)));
            }
           sort(a + 1, a + m + 1);
            
           tot = 0;
           for (int i = 1, x1, x2, y1, y2; i <= p; i++) {
               scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
               q[++tot] = node(x1 - 1, y1 - 1, i, 1);
               q[++tot] = node(x1 - 1, y2, i, -1);
               q[++tot] = node(x2, y1 - 1, i, -1);
               q[++tot] = node(x2, y2, i, 1);
           }
           sort(q + 1, q + tot + 1);
           solve();
           for (int i = 1; i <= p; i++) printf("%lld
    ", ans[i]);
        }
        return 0;
    }
    View Code

     值得注意的是,一定好好看题!!!宫殿的美丽值是其在螺旋矩阵的对于数字的各位和,就比如25,美丽值应该是2+5=7,而不是25,害得我当时赛后补题一直WA。

  • 相关阅读:
    初识《构建之法》
    实验十四 课程学习总结-韩艳艳(201671030109)
    201671030109 韩艳艳 《英文文本统计分析》结对项目报告
    201671030109 词频统计软件项目报告
    201671030109 韩艳艳 实验三作业互评与改进报告
    ----初读《构建之法》的疑虑
    201671030111 李蓉 实验十四 团队项目评审&课程学习总结
    201671030111李蓉《英文文本统计分析》结对项目报告
    201671030111 词频统计软件项目报告
    201671030111李蓉 实验三作业互评与改进报告
  • 原文地址:https://www.cnblogs.com/wizarderror/p/11449153.html
Copyright © 2011-2022 走看看