zoukankan      html  css  js  c++  java
  • Codeforces 853C

    853C - Boredom

    题意

    给出一个矩阵,每行每列有且仅有一个点。每次询问一个子矩形,问这些点构成的矩形有多少个与给定的矩形相交(两个处于对角线上的点可以组成矩形)。

    分析

    考虑矩形周围 8 个方向,答案其实就是这些方向上的点的组合。直接去算相交比较麻烦,我们可以考虑去算不相交的矩形的个数,例如上方有 (x) 个点,则要减去矩形的个数 (frac{x * (x - 1)}{2}) ,下左右同理,但是这样会多减去左下角、左上角、右上角、右下角四个区域的点组成的矩形的个数,考虑再加回来,那我们实际上就要高效算出这些区域内点的个数。二维平面统计点的个数,上主席树。

    再讲讲主席树查询的那部分,和线段树很类似(废话)。为什么它可以统计纵轴方向上某个区间点的个数呢?注意到在插入数据的时候我们是根据值的大小去决定走左边还是右边的,在查询的时候,同样根据值的大小决定走左还是走右(这个值此时是区间端点的值)。

    code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define lson l, m
    #define rson m + 1, r
    const int MAXN = 2e5 + 10;
    int L[MAXN << 5], R[MAXN << 5], sum[MAXN << 5];
    int tot;
    int f[MAXN];
    int build(int l, int r) {
        int rt = ++tot;
        sum[rt] = 0;
        if(l < r) {
            int m = l + r >> 1;
            L[rt] = build(lson);
            R[rt] = build(rson);
        }
        return rt;
    }
    int update(int pre, int l, int r, int x) {
        int rt = ++tot;
        L[rt] = L[pre]; R[rt] = R[pre]; sum[rt] = sum[pre] + 1;
        if(l < r) {
            int m = l + r >> 1;
            if(x <= m) L[rt] = update(L[pre], lson, x);
            else R[rt] = update(R[pre], rson, x);
        }
        return rt;
    }
    ll query(int ql, int qr, int l_, int r_, int l, int r) {
        if(l >= l_ && r <= r_) return sum[qr] - sum[ql];
        int m = (l + r) / 2;
        ll res = 0;
        if(m >= l_) res += query(L[ql], L[qr], l_, r_, lson);
        if(m < r_) res += query(R[ql], R[qr], l_, r_, rson);
        return res;
    }
    ll cal(ll x) { return x * (x - 1) / 2; }
    int main() {
        tot = 0;
        int n, q;
        scanf("%d%d", &n, &q);
        f[0] = build(1, n);
        for(int i = 1; i <= n; i++) {
            int x;
            scanf("%d", &x);
            f[i] = update(f[i - 1], 1, n, x);
        }
        while(q--) {
            int l, d, r, u;
            scanf("%d%d%d%d", &l, &d, &r, &u);
            ll res = cal(n) - cal(l - 1) - cal(n - r) - cal(d - 1) - cal(n - u);
            if(d > 1) {
                res += cal(query(f[0], f[l - 1], 1, d - 1, 1, n));
                res += cal(query(f[r], f[n], 1, d - 1, 1, n));
            }
            if(u < n) {
                res += cal(query(f[0], f[l - 1], u + 1, n, 1, n));
                res += cal(query(f[r], f[n], u + 1, n, 1, n));
            }
            printf("%I64d
    ", res);
        }
        return 0;
    }
    
  • 相关阅读:
    JFinal框架
    shiro认证登录实现
    linux常用的命令
    zookeeper部署到linux操作步骤
    java的冒泡排序
    软件设计的七大原则
    vue知识点整理
    JVM垃圾回收算法
    Sql Server删库了怎么办?跑路是不可能跑路的
    Linux--find用法
  • 原文地址:https://www.cnblogs.com/ftae/p/7668568.html
Copyright © 2011-2022 走看看