[Luogu 4688] [Ynoi2016]掉进兔子洞 (莫队+bitset)

题面

一个长为 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。

分析

新套路get

我们发现答案为3个区间的长度和-每个数在3个区间中出现的最小次数 $\times $ 3

考虑用bitset维护区间权值集合,注意这里要把序列中相同的2个数看作不同的2个数 。这样and一下就得到最小次数 。

我们把m个询问拆成3m个区间,但同一询问的3个区间id相同,然后按正常莫队排序,每次求出当前答案f时,把询问id对应的bitset: res[id]&=f

最后由于开n个长度为n的bitset会爆空间,我们把询问分组解决,每组t个,对t个询问跑莫队,这样就只用开t个bitset,t取25000最优

代码

//https://www.luogu.org/problem/P4688
//答案为区间长度-每个数在三个区间中出现的最小次数*3
考虑用bitset维护区间权值集合,相同的数看作不同的
and一下就得到最小次数
把询问的三个区间拆开解决,最后再合并
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<bitset>
#define maxn 100000
#define maxt 25000
using namespace std;
int n,m;
int a[maxn+5];
int tmp[maxn+5];
void discrete(){
//数字可能重复出现,bitset只能记录0和1,离散化前不能去重。
//1 2 2 3 3 ->1 2 2 4 4
//然后储存的时候用x+cnt[x]存储相同的数,如第1个2存储在3
for(int i=1;i<=n;i++) tmp[i]=a[i];
sort(tmp+1,tmp+1+n);
for(int i=1;i<=n;i++) a[i]=lower_bound(tmp+1,tmp+1+n,a[i])-tmp;
}
int bsz;
int belong[maxn+5];
struct que{
int l;
int r;
int id;
friend bool operator < (que p,que q){
if(belong[p.l]==belong[q.l]) return p.r<q.r;
else return belong[p.l]<belong[q.l];
}
}q[maxn+5];
bitset<maxn+5>f;
bitset<maxn+5>res[maxt+5];
int cntv[maxn+5];
int len[maxt+5];
void add(int val){
//第x个数,个数为cntv[x]的时候,bitset第[x+cntv[x]]位为1
f[val+cntv[val]]=1;
cntv[val]++;
}
void del(int val){
f[val+cntv[val]-1]=0;
cntv[val]--;
} void print(bitset<maxn+5> &x){
for(int i=0;i<n;i++) cout<<x[i];
printf("\n");
}
void solve(int x,int y){//分批处理
int l,r;
int cnt=0;
memset(cntv,0,sizeof(cntv));
memset(len,0,sizeof(len));
f.reset();
for(int i=x;i<=y;i++){
cnt++;
scanf("%d %d",&q[cnt].l,&q[cnt].r);
len[i-x+1]+=q[cnt].r-q[cnt].l+1;
q[cnt].id=i-x+1; cnt++;
scanf("%d %d",&q[cnt].l,&q[cnt].r);
len[i-x+1]+=q[cnt].r-q[cnt].l+1;
q[cnt].id=i-x+1; cnt++;
scanf("%d %d",&q[cnt].l,&q[cnt].r);
len[i-x+1]+=q[cnt].r-q[cnt].l+1;
q[cnt].id=i-x+1; res[i-x+1].set();//把所有位初始值设成1,方便等下直接&,如果初始为0,&完还是0
}
sort(q+1,q+1+cnt);
l=1,r=0;
for(int i=1;i<=cnt;i++){
while(l>q[i].l) add(a[--l]);
while(r<q[i].r) add(a[++r]);
//先add再del,避免删的数cnt为0造成的玄学错误
while(l<q[i].l) del(a[l++]);
while(r>q[i].r) del(a[r--]);
res[q[i].id]&=f;
} for(int i=1;i<=y-x+1;i++) printf("%d\n",len[i]-(int)res[i].count()*3);
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
discrete();
bsz=sqrt(n);
for(int i=1;i<=n;i++) belong[i]=i/bsz+1;
for(int i=1;i<=m;i+=maxt) solve(i,min(i+maxt-1,m));
}

[Luogu 4688] [Ynoi2016]掉进兔子洞 (莫队+bitset)的更多相关文章

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

    传送门 解题思路 刚开始想到了莫队+\(bitset\)去维护信息,结果发现空间不太够..试了各种奇技淫巧都\(MLE\),最后\(\%\)了发题解发现似乎可以分段做..这道题做法具体来说就是开\(3 ...

  2. BZOJ.4939.[Ynoi2016]掉进兔子洞(莫队 bitset 分组询问)

    BZOJ 洛谷 删掉的数即三个区间数的并,想到bitset:查多个区间的数,想到莫队. 考虑bitset的每一位如何对应每个数的不同出现次数.只要离散化后不去重,每次记录time就可以了. 但是如果对 ...

  3. BZOJ4939: [Ynoi2016]掉进兔子洞(莫队 bitset)

    题意 题目链接 一个长为 n 的序列 a. 有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立. 注意这里删掉指的是一个一个删,不是把等于 ...

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

    题目链接 luogu P4688 [Ynoi2016]掉进兔子洞 题解 莫队维护bitset区间交个数 代码 // luogu-judger-enable-o2 #include<cmath&g ...

  5. 洛谷P4135 Ynoi2016 掉进兔子洞 (带权bitset?/bitset优化莫队 模板) 题解

    题面. 看到这道题,我第一反应就是莫队. 我甚至也猜出了把所有询问的三个区间压到一起处理然后分别计算对应询问答案. 但是,这么复杂的贡献用什么东西存?难道要开一个数组 query_appear_tim ...

  6. luogu P4688 [Ynoi2016]掉进兔子洞

    luogu 我们要求的答案应该是三个区间长度\(-3*\)在三个区间中都出现过的数个数 先考虑数列中没有相同的数怎么做,那就是对三个区间求交,然后交集大小就是要求的那个个数.现在有相同的数,考虑给区间 ...

  7. 【洛谷 P4688】 [Ynoi2016]掉进兔子洞(bitset,莫队)

    题目链接 第一道Ynoi 显然每次询问的答案为三个区间的长度和减去公共数字个数*3. 如果是公共数字种数的话就能用莫队+bitset存每个区间的状态,然后3个区间按位与就行了. 但现在是个数,bits ...

  8. bzoj千题计划320:bzoj4939: [Ynoi2016]掉进兔子洞(莫队 + bitset)

    https://www.lydsy.com/JudgeOnline/problem.php?id=4939 ans= r1-l1+1 + r2-l2+1 +r3-l3+1 - ∑ min(cnt1[i ...

  9. BZOJ4939 Ynoi2016掉进兔子洞(莫队+bitset)

    容易发现要求三个区间各数出现次数的最小值.考虑bitset,不去重离散化后and一发就可以了.于是莫队求出每个区间的bitset.注意空间开不下,做多次即可.输出的东西错了都能调一年服了我了. #in ...

随机推荐

  1. 认识js数组

    1.认识数组 数组就是某类数据的集合,数据类型可以是整型.字符串.甚至是对象Javascript不支持多维数组,但是因为数组里面可以包含对象(数组也是一个对象),所以数组可以通过相互嵌套实现类似多维数 ...

  2. MySQL把多条数据给汇总成一条数据

    用到的是这个函数: group_concat() select group_buying_id, group_concat(app_user_ids) from org_user_group grou ...

  3. PHP培训教程 php生成WAP页面

    WAP(无线通讯协议)是在数字移动电话.个人手持设备(PDA等)及计算机之间进行通讯的开放性全球标准.由于静态的WAP页面在很多方面不能满足用户个性化的服务请求,因此通过WAP服务器端语言产生动态的W ...

  4. jAVA基础 提高文件复制性能之多线程复制文件

    利用IO流中的随机访问文件 RandomAccessFile 和文件通道 FileChanne 复制文件可大大提高文件的读写效率,在此基础上利用多线程复制文件使其性能更优.因线程的个数可根据文件的大小 ...

  5. 改变icon方向

    例你想要箭头朝上的图标而你只有箭头朝下的图标,不幸的是你又没有朝上的图标,那就旋转图标. <i class="icon iconfont _icon-iconfontfanhui4&q ...

  6. noi 1700 + 1756 八皇后问题 x

    1700:八皇后问题 总时间限制:  10000ms 内存限制:  65536kB 描述 在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方. 输入 无输入. 输出 按给定顺序和格式输出 ...

  7. 【bzoj1324】Exca王者之剑(8-9 方格取数问题)

    *题目描述: 在一个有m*n (m,n<=100)个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法, ...

  8. RabbitMQ消费端ACK与重回队列机制,TTL,死信队列详解(十一)

    消费端的手工ACK和NACK 消费端进行消费的时候,如果由于业务异常我们可以进行日志的记录,然后进行补偿. 如果由于服务器宕机等严重问题,那么我们就需要手工进行ACK保障消费端成功. 消费端重回队列 ...

  9. HTTP入门(二):用Chrome开发者工具查看 HTTP 请求与响应

    HTTP入门(二):用Chrome开发者工具查看 HTTP 请求与响应 本文简单总结HTTP的请求与响应. 本文主要目的是对学习内容进行总结以及方便日后查阅. 详细教程和原理可以参考HTTP文档(MD ...

  10. tar 打包文件

    tar支持通配符, 可以用* ?等来指定多个文件 在指明压缩文件名的时候, 一定要带上 -f选项 压缩文件名中间 最好不要带特殊符号, 如& ? * +等, shell bash 会作一些特殊 ...