bzoj4939: [Ynoi2016]掉进兔子洞

将权值排序,设权值x排序后在[l,r]出现,x在区间中出现k次,则用[l,l+k-1]为1,[l+k,r]为0来表示x的出现次数

用bitset表示可重集中每个元素的出现次数,用莫队处理出询问区间对应的bitset,通过取and后求1的个数得到答案

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
typedef unsigned int u32;
typedef u32 bits[3155];
const int N1=34007,N=N1*3;
int _(){
    int x=0,c=getchar();
    while(c<48)c=getchar();
    while(c>47)x=x*10+c-48,c=getchar();
    return x;
}
int n,m,v[N],vs[N];
struct Q{
    int l,r,id;
}qs[N];
int pos[N],ps[N];
bool operator<(Q a,Q b){
    if(pos[a.l]!=pos[b.l])return pos[a.l]<pos[b.l];
    if(a.r!=b.r)return (a.r<b.r)^(pos[a.l]&1);
    return 0;
}
int qp=0;
int qt[N],ans[N];
bits now,xs[N1];
void _flip(bits a,int x){a[x>>5]^=1<<(x&31);}
void _clr(bits a){memset(a,0,sizeof(int)*(n/32+2));}
void ins(int x){_flip(now,ps[x]++);}
void del(int x){_flip(now,--ps[x]);}
void _and(bits a,bits b){
    int mx=n/32+2;
    for(int i=0;i<mx;i+=8){
        a[0]&=b[0];
        a[1]&=b[1];
        a[2]&=b[2];
        a[3]&=b[3];
        a[4]&=b[4];
        a[5]&=b[5];
        a[6]&=b[6];
        a[7]&=b[7];
        a+=8,b+=8;
    }
}
int c1[67777];
int _and_c1(bits a,bits b){
    int mx=n/32+2,s1=0,s2=0,s3=0;
    for(int i=0;i<mx;++i){
        u32 x=a[i]&b[i];
        s1+=c1[x>>22];
        s2+=c1[x>>11&2047];
        s3+=c1[x&2047];
    }
    return s1+s2+s3;
}
void calc(){
    int B=n/sqrt(qp)+1;
    for(int i=0;i<n;++i)pos[i]=i/B,ps[v[i]]=v[i];
    _clr(now);
    for(int i=0;i<qp/3;++i)qt[i]=0;
    std::sort(qs,qs+qp);
    int L=1,R=0;
    for(int i=0;i<qp;++i){
        int l=qs[i].l,r=qs[i].r,id=qs[i].id;
        while(R<r)ins(v[++R]);
        while(L>l)ins(v[--L]);
        while(R>r)del(v[R--]);
        while(L<l)del(v[L++]);
        int t=++qt[id];
        if(t==1)memcpy(xs[id],now,sizeof(int)*(n/32+2));
        else if(t==2)_and(xs[id],now);
        else ans[id]-=_and_c1(xs[id],now)*3;
    }
    for(int i=0;i<qp/3;++i)printf("%d\n",ans[i]);
    qp=0;
}
int main(){
    for(int i=1;i<65536;++i)c1[i]=c1[i>>1]+(i&1);
    n=_(),m=_();
    for(int i=0;i<n;++i)v[i]=vs[i]=_();
    std::sort(vs,vs+n);
    for(int i=0;i<n;++i)v[i]=std::lower_bound(vs,vs+n,v[i])-vs;
    for(int i=0;i<m;++i){
        ans[qp/3]=0;
        for(int j=0;j<3;++j){
            qs[qp].l=_()-1;
            qs[qp].r=_()-1;
            qs[qp].id=qp/3;
            ans[qs[qp].id]+=qs[qp].r-qs[qp].l+1;
            ++qp;
        }
        if(qp>=(N1-7)*3||i+1==m)calc();
    }
    return 0;
}
时间: 2024-11-03 21:05:03

bzoj4939: [Ynoi2016]掉进兔子洞的相关文章

luogu P4688 [Ynoi2016]掉进兔子洞 bitset 莫队

题目链接 luogu P4688 [Ynoi2016]掉进兔子洞 题解 莫队维护bitset区间交个数 代码 // luogu-judger-enable-o2 #include<cmath> #include<bitset> #include<cstdio> #include<cstring> #include<algorithm> inline int read() { int x = 0,f = 1; char c = getchar();

bzoj 4939: [Ynoi2016]掉进兔子洞

有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立. 注意这里删掉指的是一个一个删,不是把等于这个值的数直接删完, 比如三个区间是 [1,2,2,3,3,3,3] ,  [1,2,2,3,3,3,3] 与  [1,1,2,3,3],就一起扔掉了 1 个 1,1 个 2,2 个 3. Input 第一行两个数表示 n , m. 第二行 n个数表示 a[i]. 之后 m 行,每行 6 个数 l1 , r1 , l2, r2 , l3 ,

BZOJ 4939 [Ynoi2016]掉进兔子洞(莫队+bitset)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4939 [题目大意] 给出一个数列,每个询问给出三个区间,问除去三个区间共有的数字外, 还剩下几个数字,注意删去的是共有的数字个数,不是数字种类,统计时候也一样 [题解] 首先,答案为区间长度和减去区间并数字个数和的三倍. 所以题目转化为求区间并.很显然在开始对数据可以进行离散化. 考虑每个数字只出现一次的情况,我们可以用bitset来统计区间某个数字是否存在, 莫队处理查询每个区间,

p4688 [Ynoi2016]掉进兔子洞

传送门 分析 我们考虑先将所有数离散化 之后我们对于每个状态用一个bitset来记录 其中第i段表示颜色i的信息 对于每一段信息均是段首若干1,剩余若干0表示这种颜色有多少个 于是我们不难想到莫队 答案就是1的总个数-异或值的1的个数乘3 但是我们发现开1e5*1e5的bitset会炸 于是我们考虑把1e5个询问分组,一次只考虑25000个询问 这个样子就能过了 原文地址:https://www.cnblogs.com/yzxverygood/p/10527348.html

luogu P4688 [Ynoi2016]掉进兔子洞

luogu 我们要求的答案应该是三个区间长度\(-3*\)在三个区间中都出现过的数个数 先考虑数列中没有相同的数怎么做,那就是对三个区间求交,然后交集大小就是要求的那个个数.现在有相同的数,考虑给区间中的数安排位置,即区间中如果出现了多个相同的数\(x\),那么就把第一个\(x\)放在\(x\)这种数要放的第一个位置,把第二个\(x\)放在第二个对应位置,依次类推.具体的,我们用桶维护区间内所有数的出现次数,然后给每种数安排一个初始下标\(ps_x\),使得后面过程中放数不会重叠,如果数\(x\

[bzoj 4939][Ynoi 2016]掉进兔子洞

传送门 Description 一个长为 n 的序列 a. 有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立. 注意这里删掉指的是一个一个删,不是把等于这个值的数直接删完, 比如三个区间是 [1,2,2,3,3,3,3] , [1,2,2,3,3,3,3] 与 [1,1,2,3,3],就一起扔掉了 1 个 1,1 个 2,2 个 3. Solution 弱化版是luoguP3674,这里放上它的题解 戳我 要找相同的元素就是集合求交

变量不加 var 声明——掉进坑中,无法自拔!

整整一下午,都在解决 window.onresize 中方法丢失不执行的问题!姿势固定在电脑前,颈椎病都犯了. 前些日子与大家分享了一下关于 防止jquery $(window).resize()多次执行其中方法的文章,没写全,留了一大堆问题,我理解的方法是这样的: function foo() { var resizable = null; window.onresize = function() { if (resizable) { clearTimeout(resizable) } res

C++ string中的几个小陷阱,你掉进过吗?

C++开发的项目难免会用到STL的string,使用管理都比char数组(指针)方便的多,但在得心应手的使用过程中也要警惕几个小陷阱,避免我们项目出bug却迟迟找不到原因. 1.  结构体中的string赋值问题直接通过一个例子说明,下面的例子会输出什么: #include <iostream> #include <string> #include <stdlib.h> using namespace std; struct flowRecord { string ap

人造卫星为什么会绕着地球转而不是停在太空中或者越飞越远.掉进地球的卫星为什么烧不完.

人造卫星为什么会绕着地球转而不是停在太空中或者越飞越远.掉进地球的卫星为什么烧不完.卫星被火箭推到太空中之后失去火箭的推动不就停在太空中或者因为惯性越飞越远了吗,为什么会绕着地球在椭圆形的轨道上飞?报废的卫星为什么又会掉下来?掉下来的卫星有的为什么会在大气层中没烧尽,那些卫星不是都不能耐高温的吗,应该一进大气层就熔了啊. 答: 第一点:卫星绕着地球轨道运行,不会飞出去也不会掉下来,归根到底都是万有引力的作用.可以这样类比,我们拿着绳子一头绑着石头用力做绕圈运动,绳子的拉力提供石头运行的向心力,石