ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HDU6943_二维树状数组解决三维偏序问题

2021-11-04 03:33:58  阅读:225  来源: 互联网

标签:偏序 ch HDU6943 树状 void long rd inline define


传送门

题意

给定一个 \(N \times M\) 的矩阵 \(A\),规定:点 \((x_{1}, y_{1})\) 控制 \((x_{2}, y_{2})\) 当且仅当 \(A[x_1][y_1] > A[x_2][y_2] + |x_1-x_2| + |y_1-y_2|\)

问满足上述控制条件的有序对 \(((x_1,y_1),(x_2,y_2))\) 的个数

\(N, M \le 10^3, 1 \le A[i][j] \le N + M\)

题解

将矩阵旋转三次,在四种形态中每次只考虑 \(x_1 \ge x_2, y_1 > y_2\) 的点对(后面那个不能取等,不然会重复计算);

然后就可以把绝对值拆开,就得到了 \(A[x_1][y_1] - x_1 - y_1 > A[x_2][y_2] - x_2 - y_2\) ;

不妨将每个点的权值定为 \(v = A[x][y] - x - y\) ,那么问题就转化成了一个淳朴的三维偏序问题:对于每个坐标点,求 \(x\) 小于等于它、\(y\) 小于它、\(v\) 也小于它的点的个数。

这里采用二维树状数组的做法,树状数组维护 \(y, v\) 确定的区间上出现的点的个数。由于 \(v\) 很小,不用离散化。

先按照 \(x\) 从小到大,再按照 \(y\) 从小到大的顺序遍历所有点,每次先查询 \(y, v\) 都小于它的点(加入顺序保证这些点的 \(x\) 都小于等于当前点)的个数贡献到答案,然后再把自己扔进树状数组里面。

代码

#include <bits/stdc++.h>
#define ll long long
#define MS(arr, val) memset(arr, val, sizeof(arr))
#define vi vector<int>
#define pb push_back
#define eb emplace_back
#define PI pair<int, int>
#define lll __int128
#define ull unsigned long long
#define Kases int T; rd(T); rep(kase, 1, T)
#define rep(i, a, b) for(int i = (a), __ ## i = (b); i <= __ ## i; ++i)
#define per(i, b, a) for(int i = (b), __ ## i = (a); i >= __ ## i; --i)
using namespace std;
inline void rd(char* x){scanf("%s", x);}
inline void rd(double &x){scanf("%lf", &x);}
template<typename T> inline void rd(T &x){
    x = 0; bool is = 0; char ch = getchar();
    while(!isdigit(ch)) is |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    is && (x = -x);
}
template<typename T, typename ...U> inline void rd(T &x, U &...y){rd(x), rd(y...);}
template<typename T> inline void write(T x){
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
const int maxn = 1145;
int t[maxn][maxn << 2], n, m;
inline int lb(int x){return x & (-x);}
void upd(int y, int val)
{
    for(; y <= m; y += lb(y))
        for(int i = val; i <= 2 * (n + m); i += lb(i))
            t[y][i]++;
}
ll ans = 0;
void ask(int y, int val)
{
    for(; y; y -= lb(y))
        for(int i = val; i; i -= lb(i))
            ans += t[y][i];
}
int a[maxn][maxn], b[maxn][maxn];
void rotate()
{
    rep(i, 1, n) rep(j, 1, m) b[j][n - i + 1] = a[i][j];
    swap(n, m);
    rep(i, 1, n) rep(j, 1, m) a[i][j] = b[i][j];
}
int main()
{
    while(scanf("%d%d", &n, &m) == 2)
    {
        ans = 0;
        rep(i, 1, n) rep(j, 1, m) rd(a[i][j]);
        rep(_, 0, 3)
        {
            if(_) rotate();
            rep(i, 1, n) rep(j, 1, m)
            {
                ask(j - 1, a[i][j] - i - j + n + m - 1); // v 有负数,加个偏移量
                upd(j, a[i][j] - i - j + n + m);
            }
            rep(i, 1, m) fill_n(t[i], 2 * (n + m) + 3, 0);
        }
        printf("%lld\n", ans);
    }
}

标签:偏序,ch,HDU6943,树状,void,long,rd,inline,define
来源: https://www.cnblogs.com/gxj233/p/15506459.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有