[Snoi 2017] bzoj 5016 一个简单的询问 [莫队]

Description:
infx=0r1i=l1a[i]==xr2j=l2a[j]==x ∑ x = 0 i n f ∑ i = l 1 r 1 a [ i ] == x ∑ j = l 2 r 2 a [ j ] == x


Solution:
把询问拆成四个 (l11,l21),(l11,r2),(r1,l21)(r1,r2) ( l 1 − 1 , l 2 − 1 ) , ( l 1 − 1 , r 2 ) , ( r 1 , l 2 − 1 ) ( r 1 , r 2 )
然后就可以莫队了。这里的莫队和普通的不太一样,因为涉及到两种统计。


#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, m, tot;
int a[N], cnt1[N], cnt2[N], bel[N];
long long ans[N];
struct que {
    int l, r, f, id;
    que() {}
    que(int _l, int _r, int _f, int _id) : l(_l), r(_r), f(_f), id(_id) {}
    bool friend operator < (const que &a, const que &b) {
        return bel[a.l] == bel[b.l] ? a.r < b.r : bel[a.l] < bel[b.l];
    }
} q[N];
int main() {
    scanf("%d", &n);
    int b = sqrt(n);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        bel[i] = (i - 1) / b + 1;
    }
    scanf("%d", &m);
    for(int i = 1; i <= m; ++i) {
        int l1, r1, l2, r2;
        scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
        if(l1 > 1 && l2 > 1) {
            q[++tot] = que(l1 - 1, l2 - 1, 1, i);
        }
        if(l1 > 1) {
            q[++tot] = que(l1 - 1, r2, -1, i);
        }
        if(l2 > 1) {
            q[++tot] = que(r1, l2 - 1, -1, i);
        }
        q[++tot] = que(r1, r2, 1, i);
    }
    sort(q + 1, q + tot + 1);
    int l = 0, r = 0;
    long long sum = 0;
    for(int i = 1; i <= tot; ++i) {
        while(l < q[i].l) {
            ++l;
            ++cnt1[a[l]];
            sum += cnt2[a[l]];          
        }
        while(r < q[i].r) {
            ++r;
            sum += cnt1[a[r]];
            ++cnt2[a[r]];
        }
        while(l > q[i].l) {
            --cnt1[a[l]];
            sum -= cnt2[a[l]];
            --l;
        }       
        while(r > q[i].r) {
            sum -= cnt1[a[r]];
            --cnt2[a[r]];
            --r;
        }
        ans[q[i].id] += (long long)q[i].f * sum;
    }
    for(int i = 1; i <= m; ++i) {
        printf("%lld\n", ans[i]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值