HandInDevil 的头发 (分 块)
题面
H
a
n
d
I
n
D
e
v
i
l
\rm HandInDevil
HandInDevil 的头发很油,因此随时有跳蚤跳上
H
a
n
d
I
n
D
e
v
i
l
\rm HandInDevil
HandInDevil 的头发。
现在把
H
a
n
d
I
n
D
e
v
i
l
\rm HandInDevil
HandInDevil 的头发抽象成一个数轴,一开始上面没有跳蚤。每一个时刻,有三种事件之一会发生:
- 有一个每次会跳
t
t
t 格的跳蚤跳上
H
a
n
d
I
n
D
e
v
i
l
\rm HandInDevil
HandInDevil 的头发的位置
x
x
x 。
- H
a
n
d
I
n
D
e
v
i
l
\rm HandInDevil
HandInDevil 开始挠头发,每一只跳蚤向右跳一次,跳的距离为各自的
t
t
t 。
- H
a
n
d
I
n
D
e
v
i
l
\rm HandInDevil
HandInDevil 没有挠到跳蚤,打算找下一个目标,向你询问 头发上区间
[
l
,
r
]
[l,r]
[l,r] 内跳蚤的个数。
输入
第一行一个整数
Q
Q
Q,表示事件个数。
接下来
Q
Q
Q 行描述事件,输入若干个整数:
- 若第一个数为 1 ,则接下来跟着两个整数
x
i
x_i
xi 和
t
i
t_i
ti ,表示一个跳蚤跳了上去。
- 若第一个数为 2 ,则
H
a
n
d
I
n
D
e
v
i
l
\rm HandInDevil
HandInDevil 挠了一次头发,所有跳蚤往右跳。
- 若第一个数为 3 ,则接下来跟着两个整数
l
i
l_i
li 和
r
i
r_i
ri ,你需要输出此时区间
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri] 中跳蚤的数量。
输出
对于每一个事件 3 ,输出一行一个整数,表示询问的答案。
Sample Input
10
1 4 1
1 2 2
3 3 5
2
3 3 5
2
3 3 5
3 6 6
1 5 1
3 3 5
Sample Output
1
2
0
2
1
数据范围
1
≤
Q
,
x
i
,
t
i
,
l
i
,
r
i
≤
1
0
5
,
l
i
≤
r
i
1\leq Q,x_i,t_i,l_i,r_i\leq 10^5\;,\;l_i\leq r_i
1≤Q,xi,ti,li,ri≤105,li≤ri
2 ms , 512 mb
\text{2 ms , 512 mb}
2 ms , 512 mb
题解
-既然跟 HandInDevil 扯上关系那肯定是分块题啊-
考虑分块,令块大小为
B
B
B,头发有效长度为
n
n
n,我们把
t
i
>
B
t_i> B
ti>B 的跳蚤暴力跳,然后用线段树或树状数组等数据结构维护区间和,这部分复杂度为
O
(
Q
n
B
log
n
)
O(Q\frac{n}{B}\log n)
O(QBnlogn) 。
然后对于
t
i
≤
B
t_i\leq B
ti≤B 的跳蚤,我们建立
B
B
B 棵平衡树,假设跳蚤
i
i
i 跳上时已经发生了
c
n
t
i
cnt_i
cnti 次事件 2,那么我们就把
x
i
−
c
n
t
i
∗
t
i
x_i-cnt_i*t_i
xi−cnti∗ti 加进第
t
i
t_i
ti 棵平衡树里。
询问的时候,可以先加上区间内
t
i
>
B
t_i>B
ti>B 的跳蚤数量,然后在每棵平衡树里进行询问。假设此时事件 2 发生了
c
n
t
′
cnt'
cnt′ 次,对于第
i
i
i 棵平衡树,先把
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri] 变成
[
l
i
−
c
n
t
′
∗
i
,
r
i
−
c
n
t
′
∗
i
]
[l_i-cnt'*i,r_i-cnt'*i]
[li−cnt′∗i,ri−cnt′∗i] ,然后在该平衡树里询问值在这个区间内的结点数量,加进答案。这部分复杂度是
O
(
Q
B
log
Q
)
O(QB\log Q)
O(QBlogQ) 。
由于
Q
Q
Q 和
n
n
n 同阶,所以取
B
=
n
B=\sqrt{n}
B=n
时复杂度最小,总复杂度为
O
(
Q
n
log
n
)
O(Q\sqrt n\log n)
O(Qn
logn) ,险过。
CODE
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#pragma GCC optimize(2)
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 998244353;
const int SQ = 317;
int n = 100000,m,i,j,s,o,k;
struct np{int s[2];np(){s[0]=s[1]=0;}np(int A,int B){s[0]=A;s[1]=B;}};
struct tr{
int s[2];
LL ky;int hp,siz;
tr(){s[0]=s[1]=ky=hp=siz=0;}
}tre[MAXN];
int buc[MAXN],cntb;
int newnode(LL key) {
int x = buc[cntb --]; tre[x] = tr();
tre[x].ky = key; tre[x].hp = rand()*1ll*rand()%MOD;
tre[x].siz = 1; return x;
}
int update(int x) {
if(!x) return x;
int ls = tre[x].s[0],rs = tre[x].s[1];
tre[x].siz = tre[ls].siz + tre[rs].siz + 1;
return x;
}
np spli(int x,LL key) {
np as(0,0); if(!x) return as;
int d = (tre[x].ky <= key);
as = spli(tre[x].s[d],key);
tre[x].s[d] = as.s[d^1];
as.s[d^1] = update(x);
return as;
}
np spli2(int x,int kth) {
np as(0,0); if(!x) return as;
int d = (tre[tre[x].s[0]].siz+1 <= kth);
if(d) kth -= tre[tre[x].s[0]].siz+1;
as = spli(tre[x].s[d],kth);
tre[x].s[d] = as.s[d^1];
as.s[d^1] = update(x);
return as;
}
int merg(int p1,int p2) {
if(!p1 || !p2) return p1+p2;
if(tre[p1].hp < tre[p2].hp) {
tre[p1].s[1] = merg(tre[p1].s[1],p2);
return update(p1);
}
tre[p2].s[0] = merg(p1,tre[p2].s[0]);
return update(p2);
}
int ins(int x,LL key) {
np p = spli(x,key);
return merg(p.s[0],merg(newnode(key),p.s[1]));
}
int del(int x,LL key) {
np pl = spli(x,key-1);
np pr = spli2(pl.s[1],1);
if(pr.s[0] && tre[pr.s[0]].ky == key) buc[++ cntb] = pr.s[0];
else pr.s[1] = merg(pr.s[0],pr.s[1]);
return merg(pl.s[0],pr.s[1]);
}
int query(int &x,LL l,LL r) {
if(l > r) return 0;
np p1 = spli(x,l-1);
np p2 = spli(p1.s[1],r);
int as = tre[p2.s[0]].siz;
x = merg(p1.s[0],merg(p2.s[0],p2.s[1]));
return as;
}
int bl[SQ+5],li[SQ+5],rt[SQ+5];
int c[MAXN];
void addt(int x,int y){while(x<=n)c[x]+=y,x+=lowbit(x);}
int sum(int x) {int as=0;while(x>0)as+=c[x],x-=lowbit(x);return as;}
pair<int,int> PAIR(int A,int B) {pair<int,int> a;a.FI=A;a.SE=B;return a;}
pair<int,int> q1[MAXN];
int cnq;
int main() {
freopen("flea.in","r",stdin);
freopen("flea.out","w",stdout);
m = 0;
for(int i = 100000;i > 0;i --) {
buc[++ cntb] = i;
int bid = (i+SQ-1)/SQ;
m = max(m,bid); li[bid] = i;
}
li[m+1] = 100001;
srand(time(0));
int Q = read(),cnt2 = 0;
while(Q --) {
k = read();
if(k == 1) {
s = read();o = read();
if(o > SQ) q1[++ cnq] = PAIR(s,o),addt(s,1);
else {
LL ad = (LL)s-cnt2*1ll*o;
rt[o] = ins(rt[o],ad);
}
}
else if(k == 2) {
cnt2 ++;
int leq = cnq;cnq = 0;
for(int i = 1;i <= leq;i ++) {
int ss = q1[i].FI,tt = q1[i].SE;
addt(ss,-1);
ss += tt;
if(ss <= 100000) {
addt(ss,1);
q1[++ cnq] = PAIR(ss,tt);
}
}
}
else {
s = read();o = read();
int ans = sum(o)-sum(s-1);
for(int i = 1;i <= SQ;i ++) {
LL ad1 = (LL)s-cnt2*1ll*i , ad2 = (LL)o-cnt2*1ll*i;
ans += query(rt[i],ad1,ad2);
}
printf("%d\n",ans);
}
}
return 0;
}
Better Solution
有一个更快的做法,我们把
t
i
>
B
t_i>B
ti>B 的跳蚤暴力跳时,用分块维护区间和。把头发序列分块,每个块大小为
B
B
B,修改
O
(
1
)
O(1)
O(1) ,询问
O
(
n
B
)
O(\frac{n}{B})
O(Bn),这部分修改总复杂度
O
(
Q
n
B
)
O(Q\frac{n}{B})
O(QBn),询问总复杂度
O
(
Q
n
B
)
O(Q\frac{n}{B})
O(QBn) 。
那么取块大小为
B
=
n
log
n
B=\sqrt{\frac{n}{\log n}}
B=lognn
,总复杂度就为
O
(
Q
n
log
n
)
O(Q\sqrt{n\log n})
O(Qnlogn
),实际块大小还可以根据平衡树的常数微调,比之前的做法快上不少。
CODE
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#pragma GCC optimize(2)
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 998244353;
const int SQ = 77;
int n = 100000,m,i,j,s,o,k;
struct np{int s[2];np(){s[0]=s[1]=0;}np(int A,int B){s[0]=A;s[1]=B;}};
struct tr{
int s[2];
LL ky;int hp,siz;
tr(){s[0]=s[1]=ky=hp=siz=0;}
}tre[MAXN];
int buc[MAXN],cntb;
int newnode(LL key) {
int x = buc[cntb --]; tre[x] = tr();
tre[x].ky = key; tre[x].hp = rand()*1ll*rand()%MOD;
tre[x].siz = 1; return x;
}
int update(int x) {
if(!x) return x;
int ls = tre[x].s[0],rs = tre[x].s[1];
tre[x].siz = tre[ls].siz + tre[rs].siz + 1;
return x;
}
np spli(int x,LL key) {
np as(0,0); if(!x) return as;
int d = (tre[x].ky <= key);
as = spli(tre[x].s[d],key);
tre[x].s[d] = as.s[d^1];
as.s[d^1] = update(x);
return as;
}
np spli2(int x,int kth) {
np as(0,0); if(!x) return as;
int d = (tre[tre[x].s[0]].siz+1 <= kth);
if(d) kth -= tre[tre[x].s[0]].siz+1;
as = spli(tre[x].s[d],kth);
tre[x].s[d] = as.s[d^1];
as.s[d^1] = update(x);
return as;
}
int merg(int p1,int p2) {
if(!p1 || !p2) return p1+p2;
if(tre[p1].hp < tre[p2].hp) {
tre[p1].s[1] = merg(tre[p1].s[1],p2);
return update(p1);
}
tre[p2].s[0] = merg(p1,tre[p2].s[0]);
return update(p2);
}
int ins(int x,LL key) {
np p = spli(x,key);
return merg(p.s[0],merg(newnode(key),p.s[1]));
}
int del(int x,LL key) {
np pl = spli(x,key-1);
np pr = spli2(pl.s[1],1);
if(pr.s[0] && tre[pr.s[0]].ky == key) buc[++ cntb] = pr.s[0];
else pr.s[1] = merg(pr.s[0],pr.s[1]);
return merg(pl.s[0],pr.s[1]);
}
int query(int &x,LL l,LL r) {
if(l > r) return 0;
np p1 = spli(x,l-1);
np p2 = spli(p1.s[1],r);
int as = tre[p2.s[0]].siz;
x = merg(p1.s[0],merg(p2.s[0],p2.s[1]));
return as;
}
int bl[MAXN],li[MAXN],rt[MAXN];
int ct[MAXN];
pair<int,int> PAIR(int A,int B) {pair<int,int> a;a.FI=A;a.SE=B;return a;}
pair<int,int> q1[MAXN];
int cnq;
int main() {
freopen("flea.in","r",stdin);
freopen("flea.out","w",stdout);
m = 0;
for(int i = 100000;i > 0;i --) {
buc[++ cntb] = i;
int bid = (i+SQ-1)/SQ;
m = max(m,bid); li[bid] = i;
}
li[m+1] = 100001;
srand(time(0));
int Q = read(),cnt2 = 0;
while(Q --) {
k = read();
if(k == 1) {
s = read();o = read();
if(o > SQ) q1[++ cnq] = PAIR(s,o),ct[s] ++,bl[(s+SQ-1)/SQ] ++;
else {
LL ad = (LL)s-cnt2*1ll*o;
rt[o] = ins(rt[o],ad);
}
}
else if(k == 2) {
cnt2 ++;
int leq = cnq;cnq = 0;
for(int i = 1;i <= leq;i ++) {
int ss = q1[i].FI,tt = q1[i].SE;
ct[ss] --; bl[(ss+SQ-1)/SQ] --;
ss += tt;
if(ss <= 100000) {
ct[ss] ++; bl[(ss+SQ-1)/SQ] ++;
q1[++ cnq] = PAIR(ss,tt);
}
}
}
else {
s = read();o = read();
int ans = 0;
int ll = (s+SQ-1)/SQ,rr = (o+SQ-1)/SQ;
for(int i = ll+1;i <= rr-1;i ++) ans += bl[i];
if(ll == rr) for(int i = s;i <= o;i ++) ans += ct[i];
else {
for(int i = s;(i+SQ-1)/SQ == ll;i ++) ans += ct[i];
for(int i = o;(i+SQ-1)/SQ == rr;i --) ans += ct[i];
}
for(int i = 1;i <= SQ;i ++) {
LL ad1 = (LL)s-cnt2*1ll*i , ad2 = (LL)o-cnt2*1ll*i;
ans += query(rt[i],ad1,ad2);
}
printf("%d\n",ans);
}
}
return 0;
}
HandInDevil 的头发 (分 块)的更多相关文章
- 列表 ul ol dl 和 块级标签和行及标签之间的转换
1. 无序列表 有序列表 自定义列表 1,无序列表 第一 你不必须有子标签 <li></li> 第二 ul天生自带内外边距 List-style的属性值 circle(空心圆 ...
- js瀑布流 原理实现揭秘 javascript 原生实现
web,js瀑布流揭秘 瀑布流再很久之前流行,可能如我一样入行晚的 ,可能就没有机会去使用.但是这个技术终究是个挺炫酷的东西,花了一个上午来研究,用原生js实现了一个,下面会附上源码,供大家解读. 说 ...
- ASP.NET 文件下载
using System; using System.Web; using System.IO; public partial class _Default : System.Web.UI.Page ...
- 漫话JavaScript与异步·第一话——异步:何处惹尘埃
自JavaScript诞生之日起,频繁与异步打交道便是这门语言的使命,并为此衍生出了许多设计和理念.因此,深入理解异步的概念对于前端工程师来说极为重要. 什么是异步? 程序是分"块" ...
- css小知识 2
效果为 为什么还出现出现不同的效果? 浏览器在解析第二个p的时候,因为第二个字母见没有空格,它会认为这是一个单词没有写完,所以不会换行 列表 1.无序列表ul 第二,内部必须有子代标签<li&g ...
- http状态码 以及请求响应头相关
1xx消息[编辑] 这一类型的状态码,代表请求已被接受,需要继续处理.这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束.由于HTTP/1.0协议中没有定义任何1xx状态码,所以除非 ...
- HTML知识梳理(笔记)
HTML常见元素 meta 定义和用法<meta> 元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词. <meta> 标 ...
- 操作系统之IO管理
IO系统结构 设备的分类 按数据组织分 块设备: 信息的存取总是以数据块为单位. 它属于有结构设备,如磁盘等. 磁盘设备的基本特征是传输速率较高,以及可寻址,即对它可随机地读/写任一块. 字符设备: ...
- TCP/IP基础总结性学习(6)
HTTP 首部 一. HTTP 报文首部 1.HTTP 报文的结构: 2.HTTP 请求报文 图示: 举例子: 3.HTTP 响应报文: 下面的示例是访问 http://hackr.jp 时,请求报文 ...
随机推荐
- fpm工具安装
概述 最近在对机房的编译环境做整理,过程曲折而痛苦,记录一下. 之前的一个老项目,在打包的时候用到了一个叫做fpm的工具. 编译环境涉及centos6和centos7,在新的编译环境的过程中,如何安装 ...
- 隐式转换导致的cpu负载近100%
1.背景:从昨天晚上通过钉钉和邮箱一直接收到频繁报cpu负载超过90%,刚好BI同事晚上.凌晨在线上配合审计频繁DML数据库(备注:BI有一个同事有个库的DML权限,后面等审计完会收回)加上我线上线下 ...
- 【Golang】程序如何优雅的退出?
1. 背景 项目开发过程中,随着需求的迭代,代码的发布会频繁进行,在发布过程中,如何让程序做到优雅的退出? 为什么需要优雅的退出? 你的 http 服务,监听端口没有关闭,客户的请求发过来了,但处理了 ...
- WAVE音频格式及及转换代码
音频信号的读写.播放及录音 python已经支持WAV格式的书写,而实时的声音输入输出需要安装pyAudio(http://people.csail.mit.edu/hubert/pyaudio).最 ...
- 2 万字 + 30 张图 | 细聊 MySQL undo log、redo log、binlog 有什么用?
作者:小林coding 计算机八股文网站:https://xiaolincoding.com/ 大家好,我是小林. 从这篇「执行一条 SQL 查询语句,期间发生了什么?」中,我们知道了一条查询语句经历 ...
- Vue3.0系列——「vue3.0性能是如何变快的?」
前言 先学习vue2.x,很多2.x内容依然保留: 先学习TypeScript,vue3.0是用TS重写的,想知其然知其所以然必须学习TS. 为什么学习vue3.0? 性能比vue2.x快1.2-2倍 ...
- Consider defining a bean of type 'redis.clients.jedis.JedisPool' in your configuration.
报错信息 原因是没有Jedispool没有注入 import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml ...
- 从UI Designer上面动态创建下拉列表
在UI Desigher上创建一个新的列表 并创建2个值,code 和value 添加一个EventHandler 在EventHandler上面添加一个Operation 类型为script$dat ...
- 鹏城杯 WEB_WP
简单的PHP GET /?code=[~%8C%86%8C%8B%9A%92][~%CF]([~%9A%91%9B][~%CF]([~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A ...
- 【docker专栏5】详解docker镜像管理命令
一.国内Docker镜像仓库 由于大家都知道的原因,从国外的docker 仓库中pull镜像的下载速度实际上是很慢的.国内的一些一线厂商以及docker官方都在国内免费提供了一些docker镜像仓库, ...