zoukankan      html  css  js  c++  java
  • bzoj5016 [SNOI2017]一个简单的询问

    bzoj5016 [SNOI2017]一个简单的询问

    给你一个长度为 (N) 的序列 (a_i)(1leq ileq N) ,和 (Q) 组询问,每组询问读入 (l_1, r_1, l_2, r_2) ,需输出

    [sumlimits_{x=0}^infty ext{get}(l_1, r_1, x)cdot ext{get}(l_2, r_2, x) ]

    ( ext{get}(l, r, x)) 表示计算区间 ([l, r]) 中,数字 (x) 出现了多少次。

    (1leq N, Qleq5 imes10^4, a_iin[1, N])

    莫队


    如果直接暴力莫队,时间复杂度是假的(

    首先,如果 (l_1=l_2=1) ,是可以直接用莫队 (O(sqrt n)) 求出的

    现在把询问拆成 ([1, x][1, y]) 的形式

    (A_1=[l_1, r_1], A_2=[l_2, r_2], B_1=[1, l_1-1], B_2=[1, l_2-1])

    先看看 ((A_1+B_1)(A_2+B_2)) 是什么

    (A_1A_2+A_1B_2+A_2B_1+B_1B_2)

    (A_1A_2, B_1B_2) 是可以直接求的

    再把 (A_1B_2) 拆成 ((A_1+B_1)B_2-B_1B_2) ,把 (A_2B_1) 拆成 ((A_2+B_2)B_1-B_1B_2)

    ( herefore) $$(A_1+B_1)(A_2+B_2)=A_1A_2+(A_1+B_1)B_2+(A_2+B_2)B_1-B_1B_2$$

    ( herefore) $$A_1A_2=(A_1+B_1)(A_2+B_2)-(A_1+B_1)B_2-(A_2+B_2)B_1+B_1B_2$$

    容易发现,上式右侧每一项都是形如 ([1, x]) 的,然后就上莫队辣

    时间复杂度 (O(sqrt n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int maxn = 5e4 + 10;
    ll ans[maxn];
    int n, m, tot, bsz, a[maxn], bl[maxn], c1[maxn], c2[maxn];
    
    struct Query {
      int l, r, op, tid;
      Query(int _l = 0, int _r = 0, int _o = 0, int _t = 0) :
        l(_l), r(_r), op(_o), tid(_t) {}
      bool operator < (const Query& o) const {
        return bl[l] == bl[o.l] ? r > o.r : l < o.l;
      }
    } Q[maxn << 2];
    
    int main() {
      scanf("%d", &n);
      bsz = sqrt(n);
      for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
        bl[i] = (i - 1) / bsz + 1;
      }
      scanf("%d", &m);
      for (int i = 1; i <= m; i++) {
        int l1, l2, r1, r2;
        scanf("%d %d %d %d", &l1, &r1, &l2, &r2);
        Q[++tot] = Query(r1, r2, 1, i);
        if (l1 > 1) Q[++tot] = Query(l1 - 1, r2, -1, i);
        if (l2 > 1) Q[++tot] = Query(r1, l2 - 1, -1, i);
        if (l1 > 1 && l2 > 1) Q[++tot] = Query(l1 - 1, l2 - 1, 1, i);
      }
      sort(Q + 1, Q + tot + 1);
      int l = 0, r = 0; ll now = 0;
      for (int i = 1; i <= tot; i++) {
        while (l < Q[i].l) {
          l++, c1[a[l]]++, now += c2[a[l]];
        }
        while (l > Q[i].l) {
          c1[a[l]]--, now -= c2[a[l]], l--;
        }
        while (r < Q[i].r) {
          r++, c2[a[r]]++, now += c1[a[r]];
        }
        while (r > Q[i].r) {
          c2[a[r]]--, now -= c1[a[r]], r--;
        }
        ans[Q[i].tid] += Q[i].op * now;
      }
      for (int i = 1; i <= m; i++) {
        printf("%lld
    ", ans[i]);
      }
      return 0;
    }
    
  • 相关阅读:
    getBoundingClientRect()方法
    Sublime Text3 安装less
    less知识点总结(一)
    跨域知识(二)——JSONP
    面向过程和面向对象的区别(转)
    暴力+DP:买卖股票的最佳时机
    车的可用捕获量(3.26leetcode每日打卡)
    三维形体的表面积(3.25leetcode每日打卡)
    基础练习:FJ的字符串
    DP:打家劫舍
  • 原文地址:https://www.cnblogs.com/Juanzhang/p/10605613.html
Copyright © 2011-2022 走看看