首页 > 其他 > 详细

Luogu4688 [Ynoi2016]掉进兔子洞 【莫队,bitset】

时间:2019-10-04 23:17:53      阅读:105      评论:0      收藏:0      [点我收藏+]

题目链接:洛谷

我们知道要求的是\([l_1,r_1],[l_2,r_2],[l_3,r_3]\)的可重集取交的大小,肯定是要用bitset的,那怎么做可重集呢?

那就是要稍微动点手脚,首先在离散化的时候,将\(a_x\)设为\(\leq a_x\)的数的个数,然后再插入一个数的时候,将\(a_x-cnt_{a_x}\)设为1,删除的时候设为0,然后直接取交就可以了。正确性比较显然。

还有一个问题就是如何存下\(100000*100000\)的bitset,那肯定是存不下的,所以把询问分成3部分,然后每块分别做就可以用时间换空间了。

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef long long LL;
const int N = 100010, M = 33340;
int n, m, _n, len, a[N], val[N], cnt[N], ql, qr, tmp[M];
bitset<N> ans[M], now;
struct Query {
    int l, r, id;
    inline bool operator < (const Query &o) const {
        if(l / len != o.l / len) return l / len < o.l / len;
        if(l / len & 1) return r > o.r;
        return r < o.r;
    }
} que[N];
inline void add(int x){++ cnt[x]; now[x - cnt[x]] = 1;}
inline void del(int x){now[x - cnt[x]] = 0; -- cnt[x];}
inline void solve(int m){
    for(Rint i = 1;i <= n;i ++) cnt[i] = 0;
    for(Rint i = 1;i <= m;i ++) ans[i].set(), tmp[i] = 0; now.reset(); ql = 1; qr = 0;
    for(Rint i = 1;i <= 3 * m;i ++) scanf("%d%d", &que[i].l, &que[i].r), tmp[que[i].id = (i + 2) / 3] += que[i].r - que[i].l + 1;
    sort(que + 1, que + 3 * m + 1);
    for(Rint i = 1;i <= 3 * m;i ++){
        while(ql > que[i].l) add(a[-- ql]);
        while(qr < que[i].r) add(a[++ qr]);
        while(qr > que[i].r) del(a[qr --]);
        while(ql < que[i].l) del(a[ql ++]);
        ans[que[i].id] &= now;
    }
    for(Rint i = 1;i <= m;i ++) printf("%d\n", tmp[i] - 3 * ans[i].count());
}
int main(){
    scanf("%d%d", &n, &m); len = sqrt(n);
    for(Rint i = 1;i <= n;i ++) scanf("%d", a + i), val[i] = a[i];
    sort(val + 1, val + n + 1);
    _n = unique(val + 1, val + n + 1) - val - 1;
    for(Rint i = 1;i <= n;i ++) a[i] = lower_bound(val + 1, val + _n + 1, a[i]) - val;
    for(Rint i = 1;i <= _n;i ++) val[i] = 0;
    for(Rint i = 1;i <= n;i ++) ++ val[a[i]];
    for(Rint i = 1;i <= _n;i ++) val[i] += val[i - 1];
    for(Rint i = 1;i <= n;i ++) a[i] = val[a[i]];
    solve(m / 3); solve((m + 1) / 3); solve((m + 2) / 3);
}

Luogu4688 [Ynoi2016]掉进兔子洞 【莫队,bitset】

原文:https://www.cnblogs.com/AThousandMoons/p/11623510.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!