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;
    }
    
  • 相关阅读:
    GPIO推挽输出和开漏输出详解
    Linux驱动中completion接口浅析(wait_for_complete例子,很好)【转】
    当JAVA集合移除自身集合元素时发生的诸多问题
    Machine Learning #Lab1# Linear Regression
    Nth to Last Node in List
    Codeforces Round #272 (Div. 2)AK报告
    iOS 使用Block实现函数回调
    ios上禁止输入表情
    POJ 1287:Networking(最小生成树Kruskal)
    CSS实现强制换行-------Day 78
  • 原文地址:https://www.cnblogs.com/ftae/p/7668568.html
Copyright © 2011-2022 走看看