【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 ...
随机推荐
- 简单的windows作业管理(自己也没弄透彻)
先把代码贴出来,以后有时间再研究!简单的说,作业就相当于沙箱,可以使程序在一定范围内活动. #include "stdafx.h"#include "windows.h& ...
- 生产环境该如何选择lvs的工作模式,和哪一种算法
lvs的工作模式有这几种: 1.RR : 轮叫算法,平均分配,你一个,我一个: 2.WRR :加权轮叫算法,谁的处理能力强,谁的权重就高: 3.LC :最少链接算法,谁的连接数最少,谁就处理更多的链接 ...
- 浅谈Android四大组建之一Service---Service与Activity的绑定
从上一篇文章我们学会了如何创建Service,我们通过监听一个按钮,然后再按钮里面通过意图来启动Service.但是我们有没有发现,启动服务以后,Activity和Service之间的联系好像就断开了 ...
- for xml path 按分类合并行数据
) as itemnum FROM ( SELECT Sonum, (SELECT ItemNum+',' FROM testtb WHERE Sonum=A.Sonum FOR XML ...
- C++指针作为函数的参数进行传递时注意的问题
应注意问题: 当指针作为函数的参数进行传递的时候,本质上还是进行的"值传递",也就是复制了一个新的指向该地址的指针变量. 只有在被调函数中,对指针进行引用操作,才可以达到不需要返回 ...
- 基于unity3d的RRT算法路径规划
- 关于MySQL隐式转换
一.如果表定义的是varchar字段,传入的是数字,则会发生隐式转换. 1.表DDL 2.传int的sql 3.传字符串的sql 仔细看下表结构,rid的字段类型: 而用户传入的是int,这里会有一个 ...
- p3203 弹飞绵羊
传送门 分析 基本的lct操作,建一个点N表示弹飞出去的点,每次输出N的左子树的大小即可 代码 #include<iostream> #include<cstdio> #inc ...
- 树莓派研究笔记(2)-- 安装Nginx 服务器,PHP 和 SQLite
1. 安装nginx web 服务器 sudo apt-get install nginx 2. 启动nginx,nginx的www目录默认在/usr/share/nginx/html中 sudo / ...
- auto和register关键字
关键字概述 很多朋友看到这儿可能会有疑问,往往其它讲C语言的书籍都是从HelloWorld,数据类型开始C语言学习的,为什么我们要从C语言的关键字开始呢?关于这点,我有两点需要说明: 本章节面向的读者 ...