【BZOJ2639】矩形计算(四维偏序)

Description

输入一个n*m的矩阵,矩阵的每一个元素都是一个整数,然后有q个询问,每次询问一个子矩阵的权值。矩阵的权值是这样定义的,对于一个整数x,如果它在该矩阵中出现了p次,那么它给该矩阵的权值就贡献p2。


Solution

由于出现 p p p次的元素的贡献是 p 2 p^2 p2,我们可以看做每一对相同的元素可以产生 1 1 1的贡献。

我们定一个 S S S,大概为 40 40 40
对于出现次数大于 S S S的元素,由于这样的元素个数不多,直接暴力搞。
对于小于 S S S的元素,我们两两配对,由于要求在矩形范围内,有 4 4 4个限制,所以是个四维偏序问题,将第一维排序,剩下的用三维树状数组即可。


Code

#include<bits/stdc++.h>
  
using namespace std;
  
typedef long long LL;
typedef long double LD;
typedef pair<int, int> PII;
#define Rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define X first
#define Y second
#define PB(a) push_back(a)
#define MP(a, b) make_pair(a, b)
#define SZ(a) ((int)(a).size())
#define ALL(a) a.begin(), a.end()
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia
#define sqr(x) ((x) * (x))
  
template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
  
inline int read() {
    static int _, __; static char c_;
    for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
    for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
    return _ * __;
}
//EOT
  
  
const int maxn = 233, maxm = 233 * 233, S = 35, sumc = maxm / S + 5, maxq = 201314;
  
int n, m, q, ls[maxm], lss, ans[maxq], ty[maxm], cnt[maxm], a[maxn][maxn];
  
struct Query {
    int x1, y1, x2, y2;
}qry[maxq];
  
namespace FuckYouAll {
    int lss, ls[maxm], sum[maxn][maxn];
    inline void Main() {
        For(k, 1, lss) {
            For(i, 1, n) For(j, 1, m)
                sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + (a[i][j] == ls[k]);
            For(p, 1, q) {
                ans[p] += sqr(sum[qry[p].x2][qry[p].y2] + sum[qry[p].x1 - 1][qry[p].y1 - 1]
                        - sum[qry[p].x1 - 1][qry[p].y2] - sum[qry[p].x2][qry[p].y1 - 1]);
            }
        }
    }
}
  
namespace LoveYouForever {
    int lss, ls[maxn * maxn];
  
    struct Point { int a, b, c, d, id; }p[S * maxm + maxq];
    int ps;
    inline bool cmp(Point A, Point B) {
        if (A.a != B.a) return A.a < B.a;
        if (A.b != B.b) return A.b < B.b;
        if (A.c != B.c) return A.c < B.c;
        if (A.d != B.d) return A.d < B.d;
        return A.id < B.id;
    }
  
    struct BIT {
        int c[maxn][maxn][maxn];
#define lb(x) ((x) & -(x))
        inline void update(int x, int y, int z) {
            for (int i = x; i <= m; i += lb(i))
                for (int j = y; j <= n; j += lb(j))
                    for (int k = z; k <= m; k += lb(k))
                        ++ c[i][j][k];
        }
        inline int query(int x, int y, int z) {
            int ans = 0;
            for (int i = x; i; i -= lb(i))
                for (int j = y; j; j -= lb(j))
                    for (int k = z; k; k -= lb(k))
                        ans += c[i][j][k];
            return ans;
        }
    }bit;
  
    vector<PII> vct[maxm];
  
    inline void Main() {
        For(i, 1, n) For(j, 1, m) if (ty[a[i][j]] == 2)
            vct[lower_bound(ls + 1, ls + 1 + lss, a[i][j]) - ls].push_back(MP(i, j));
        For(i, 1, lss) {
            Rep(j, SZ(vct[i])) Rep(k, SZ(vct[i])) {
                int x1 = vct[i][j].X, y1 = vct[i][j].Y, x2 = vct[i][k].X, y2 = vct[i][k].Y;
                if (x1 > x2) swap(x1, x2);
                if (y1 > y2) swap(y1, y2);
                p[++ ps] = (Point){n - x1 + 1, m - y1 + 1, x2, y2, 0};
            }
        }
        For(i, 1, q)
            p[++ ps] = (Point){n - qry[i].x1 + 1, m - qry[i].y1 + 1, qry[i].x2, qry[i].y2, i};
        sort(p + 1, p + 1 + ps, cmp);
        //For(i, 1, ps) cout << p[i].a << ' ' << p[i].b << ' ' << p[i].c << ' ' << p[i].d << ' ' << p[i].id<< endl;
        For(i, 1, ps)
            if (!p[i].id) bit.update(p[i].b, p[i].c, p[i].d);
            else ans[p[i].id] += bit.query(p[i].b, p[i].c, p[i].d);
    }
}
  
int main()
{
#ifdef hany01
    freopen("vegetable.in", "r", stdin);
    freopen("vegetable.out", "w", stdout);
#endif
  
    n = read(), m = read();
    For(i, 1, n) For(j, 1, m) ls[(i - 1) * m + j] = a[i][j] = read();
    sort(ls + 1, ls + 1 + n * m), lss = unique(ls + 1, ls + 1 + n * m) - ls - 1;
    For(i, 1, n) For(j, 1, m) ++ cnt[a[i][j] = lower_bound(ls + 1, ls + 1 + lss, a[i][j]) - ls];
    For(i, 1, lss)
        if (cnt[i] > S) FuckYouAll::ls[++ FuckYouAll:: lss] = i, ty[i] = 1;
        else LoveYouForever:: ls[++ LoveYouForever:: lss] = i, ty[i] = 2;
	q = read();
    For(i, 1, q) {
		qry[i].x1 = read(), qry[i].y1 = read(), qry[i].x2 = read(), qry[i].y2 = read();
		if (qry[i].x1 > qry[i].x2) swap(qry[i].x1, qry[i].x2);
		if (qry[i].y1 > qry[i].y2) swap(qry[i].y1, qry[i].y2);
	}
  
    FuckYouAll:: Main();
    LoveYouForever:: Main();
    For(i, 1, q) printf("%d\n", ans[i]);
  
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值