【bzoj4939】【YNOI2016】掉进兔子洞(莫队)
题目描述
您正在打galgame,然后突然发现您今天太颓了,于是想写个数据结构题练练手: 一个长为 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。
输入输出格式
输入格式:
第一行两个数表示 n , m。
第二行 n个数表示 a[i]。
之后 m 行,每行 6 个数 l1 , r1 , l2, r2 , l3 , r3 表示这三个区间。
输出格式:
对于每个询问,输出一个数表示答案。
输入输出样例
说明
n , m <= 100000 , 1 <= a[i] <= 1000000000
题解
大毒瘤题名不虚传……
做莫队的时候因为先del再add已经快RE到死了……
据某加藤大佬说这题一看就是莫队+bitset维护并集,然而我啥都看不出来……
先把原数组给离散,然后总共只有$10^5$个数,可以对每一个询问维护一个bitset,表示每一位有几个,然后只要把三个询问的bitset并起来就行了。然而bitset怎么表示数的个数呢?我们可以给每一个数很多位置,位置数为它在原数组中的个数。比方说1,1,4,3,1,那么我们就给1这个数字3个位置,做莫队的时候,维护一个bitset,设当前已经有x个1,且1在bitset中的位置为1,那么要add的时候,就让第x+1位变为1,表示加了一个1,del的话,就让第x位变为0,表示少了一个1,同时更新x
然后这样有可能两个数的区间重叠,那么我们在离散化的之后可以不去重,直接用在排序后的数组的位置表示新数,这样每一个数就不会和其他区间重叠了
//minamoto
#include<iostream>
#include<cstdio>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(int x){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+,NN=;
int n,m,len,rt[N],ans[N];
bitset<N> f[NN+],tmp;
int a[N],b[N],L1[N],R1[N],L2[N],R2[N],L3[N],R3[N],cnt[N],l,r,tot;
bool flag[NN+];
struct node{
int l,r,id;
node(){}
node(int l,int r,int id):l(l),r(r),id(id){}
}q[N];
inline bool operator <(node a,node b){
return rt[a.l]==rt[b.l]?rt[a.l]&?a.r<b.r:a.r>b.r:rt[a.l]<rt[b.l];
}
inline void init(){
memset(cnt,,sizeof(cnt));
memset(flag,,sizeof(flag));
tmp.reset();
l=,r=,tot=;
}
inline void add(int x){
tmp[x+cnt[x]]=,++cnt[x];
}
inline void del(int x){
tmp[x+cnt[x]-]=,--cnt[x];
}
inline void solve(int lx,int rx){
init();
for(int i=lx;i<=rx;++i){
q[++tot]=node(L1[i],R1[i],i),ans[i]+=R1[i]-L1[i]+;
q[++tot]=node(L2[i],R2[i],i),ans[i]+=R2[i]-L2[i]+;
q[++tot]=node(L3[i],R3[i],i),ans[i]+=R3[i]-L3[i]+;
}
sort(q+,q++tot);
for(int i=;i<=tot;++i){
while(l>q[i].l) add(a[--l]);
while(r<q[i].r) add(a[++r]);
while(l<q[i].l) del(a[l++]);
while(r>q[i].r) del(a[r--]);
if(!flag[q[i].id-lx+]) flag[q[i].id-lx+]=,f[q[i].id-lx+]=tmp;
else f[q[i].id-lx+]&=tmp;
}
for(int i=lx;i<=rx;++i) ans[i]-=f[i-lx+].count()*;
}
int main(){
n=read(),m=read(),len=sqrt(n);
for(int i=;i<=n;++i) a[i]=b[i]=read(),rt[i]=(i-)/len+;
sort(b+,b++n);
for(int i=;i<=n;++i) a[i]=lower_bound(b+,b++n,a[i])-b;
for(int i=;i<=m;++i)
L1[i]=read(),R1[i]=read(),L2[i]=read(),R2[i]=read(),L3[i]=read(),R3[i]=read();
for(int i=;i<=m;i+=NN) solve(i,min(m,i+NN-));
for(int i=;i<=m;++i) print(ans[i]);
Ot();
return ;
}
【bzoj4939】【YNOI2016】掉进兔子洞(莫队)的更多相关文章
- BZOJ4939: [Ynoi2016]掉进兔子洞(莫队 bitset)
题意 题目链接 一个长为 n 的序列 a. 有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立. 注意这里删掉指的是一个一个删,不是把等于 ...
- [Luogu 4688] [Ynoi2016]掉进兔子洞 (莫队+bitset)
[Luogu 4688] [Ynoi2016]掉进兔子洞 (莫队+bitset) 题面 一个长为 n 的序列 a.有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间 ...
- BZOJ.4939.[Ynoi2016]掉进兔子洞(莫队 bitset 分组询问)
BZOJ 洛谷 删掉的数即三个区间数的并,想到bitset:查多个区间的数,想到莫队. 考虑bitset的每一位如何对应每个数的不同出现次数.只要离散化后不去重,每次记录time就可以了. 但是如果对 ...
- BZOJ 4939: [Ynoi2016]掉进兔子洞(莫队+bitset)
传送门 解题思路 刚开始想到了莫队+\(bitset\)去维护信息,结果发现空间不太够..试了各种奇技淫巧都\(MLE\),最后\(\%\)了发题解发现似乎可以分段做..这道题做法具体来说就是开\(3 ...
- BZOJ4939 Ynoi2016掉进兔子洞(莫队+bitset)
容易发现要求三个区间各数出现次数的最小值.考虑bitset,不去重离散化后and一发就可以了.于是莫队求出每个区间的bitset.注意空间开不下,做多次即可.输出的东西错了都能调一年服了我了. #in ...
- 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 ...
- bzoj4939: [Ynoi2016]掉进兔子洞
将权值排序,设权值x排序后在[l,r]出现,x在区间中出现k次,则用[l,l+k-1]为1,[l+k,r]为0来表示x的出现次数 用bitset表示可重集中每个元素的出现次数,用莫队处理出询问区间对应 ...
- luogu P4688 [Ynoi2016]掉进兔子洞 bitset 莫队
题目链接 luogu P4688 [Ynoi2016]掉进兔子洞 题解 莫队维护bitset区间交个数 代码 // luogu-judger-enable-o2 #include<cmath&g ...
- BZOJ 4939 [Ynoi2016]掉进兔子洞(莫队+bitset)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4939 [题目大意] 给出一个数列,每个询问给出三个区间,问除去三个区间共有的数字外, ...
- 【洛谷 P4688】 [Ynoi2016]掉进兔子洞(bitset,莫队)
题目链接 第一道Ynoi 显然每次询问的答案为三个区间的长度和减去公共数字个数*3. 如果是公共数字种数的话就能用莫队+bitset存每个区间的状态,然后3个区间按位与就行了. 但现在是个数,bits ...
随机推荐
- Day3(2)bash的特性
bash的基础特性: (1)命令历史 history 环境变量: HISTSIZE:命令零食记录的条数: HISTFILE:~/.bash_history: HISFILESIZE:命令历史文件记录历 ...
- maven如何过滤占位符
今天遇到一个问题,就是properties文件中赋值用的这种形式${xxx},真正的值是配置在pom的profile中,但是未生效. 后来找到原因,原来是pom中少了一段代码: <build&g ...
- 单片机RS485通信接口、控制线、原理图及程序实例
RS232 标准是诞生于 RS485 之前的,但是 RS232 有几处不足的地方: 接口的信号电平值较高,达到十几 V,使用不当容易损坏接口芯片,电平标准也与TTL 电平不兼容. 传输速率有局限,不可 ...
- List转Datable(需区分对象充当List成员和数组充当List成员两种情况)
对象充当List成员时: /// <summary> /// 将泛类型集合List类转换成DataTable /// </summary> /// <param name ...
- 2016.8.17服务器端数据库用户导入导出方法 expdp和impdp
EXP和IMP是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用. EXPDP和IMPDP是服务端的工具程序,他们只能在ORACLE服务端使用,不能在客户端使用. IMP只适用于EXP导出的 ...
- oracle常用函数总结(一)
最近在读数据库存储过程,或者在xml里写sql时用到数据库函数,笔者觉得有必要总结一下,当然有的函数笔者也很懵逼,不过可以问度娘啊!好了!开始正题. )s from dual;--1 若nvl第一个参 ...
- 【Android 多媒体应用】使用MediaRecoder录制,MediaPlayer播放音频数据
1.MainActivity.java import android.annotation.TargetApi; import android.app.Activity; import android ...
- C语言学习笔记--字符串
字符串是有序字符的集合,C 语言中没有字符串的概念,而是通过特殊的字符数组模拟字符串,是以'\0'结尾的字符数组. 1.字符数组与字符串 (1)在 C 语言中,字双引号引用的单个或多个字符是一种特殊的 ...
- xcode 编译报错“Cannot create __weak reference in file using manual reference counting”解决办法<转>
http://blog.csdn.net/ouq68/article/details/51003876 解决方法: Please set ‘Weak References in Manual Reta ...
- auth 权限控制
一. 权限介绍所谓权限控制,大部分是在管理后台上使用.比如超级管理员登录,会得到所有操作的控制权:认证专员,只能给会员做认证操作:审核专员,只能操作内容的审核.删除.加精等操作,以此类推.那么 Thi ...