[loj6278]数列分块入门2
做法1
以$K$为块大小分块,并对每一个块再维护一个排序后的结果,预处理复杂度为$o(n\log K )$
区间修改时将整块打上标记,散块暴力修改并归并排序,单次复杂度为$o(\frac{n}{K}+K)$
区间查询时在整块中二分,散块暴力枚举,单次复杂度为$o(\frac{n}{K}\log K+K)$
显然取块大小为$K=\sqrt{n\log n}$时最优,单次复杂度均为$o(n\sqrt{n\log n})$
时间复杂度为$o(n\log n)-o(\sqrt{n\log n})$
做法2
瓶颈显然在于整块的二分,考虑对其批量处理
具体的,对于整块的询问先记录在该块上而不执行,在当一个块要被作为散块暴力修改时再处理之前记录的所有操作(标记可以先减去,注意到该块的序列在这次修改前不会变化)
将这些询问基数排序(当底数较大时可以认为是线性的),再利用单调性进行查询,即做到了这样的查询均摊线性(注意$o(K)$的复杂度暴力修改本来就有),那么取$K=\sqrt{n}$即可
时间复杂度为$o(n\log n)-o(\sqrt{n})$
做法3
实际上是在$\frac{n}{K}$个长为$K$的序列中二分,那么即可使用类似[luogu6466]分散层叠算法的做法
具体的,再选择一个阈值$B$,并将连续$B$个块称为一组,对每一组仅考虑每一个块中(排序后)下标是$B$的倍数的位置,即构成$B$个长度为$\frac{K}{B}$的序列,对其使用做法4维护
预处理的复杂度即为$o(\frac{n}{BK}\cdot K)=o(\frac{n}{B})$(当然还有$o(n\log n)$的排序复杂度)
区间修改时将整组和整块打上标记,散组和散块都暴力修改,单次复杂度为$o(\frac{n}{K}+K)$
区间查询时,将位置分为以下三类:
1.对整组直接查询,至多$o(\frac{n}{BK})$组,每组的复杂度为$o(B\log B+\log BK)$(可以$o(B+\log BK)$找到每一个块中第一个下标是$B$的倍数且大于等于$x^{2}$的数,再向前$B$个位置二分即可)
2.对散组的整块二分查询,至多$o(B)$个块,每块的复杂度为$o(\log K)$
3.对散组的散块暴力查询,至多$o(K)$个位置,复杂度也为$o(K)$
综上,单次复杂度为$o(K+\frac{n}{K}\log B+\frac{n}{BK}\log BK)$,显然取$K=\sqrt{n\log \log n},B=\log n$最优
时间复杂度为$o(n\log n)-o(\sqrt{n\log\log n})$
做法4
同样使用[luogu6466]分散层叠算法的做法,但考虑做法4沿用做法3的部分
具体的,直接对$\frac{n}{K}$个块建立一个分治结构(也即线段树),并且以$\frac{1}{3}$的比例取元素(即合并时仅取下标是3的倍数的位置上的元素),此时序列长度和即为$o(n)$(当然取偶数位置也是$o(n)$的)
区间修改时对整块打上标记(即线段树),并对散块暴力修改后重新维护,注意到一个叶子节点到根路径上的序列长度依次为$K,\frac{2}{3}K,\frac{4}{9}K,...$,那么总和即为$o(K)$,也即单次复杂度为$o(\log \frac{n}{K}+K)$
区间查询时对整块直接在该结构上查询,只需要在根上二分一次并递归,注意到一共只有$o(\frac{n}{K})$个节点,因此这部分的复杂度为$o(\log K+\frac{n}{K})$,散块暴力复杂度仍为$o(K)$
综上,单次复杂度为$o(K+\frac{n}{K})$,显然取$K=\sqrt{n}$最优
时间复杂度为$o(n\log n)-o(\sqrt{n})$
1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 50005
4 #define K 300
5 #define D 3
6 #define ll long long
7 #define L (k<<1)
8 #define R (L+1)
9 #define mid (l+r>>1)
10 int n,k,p,l,r,x,ans,num[11],id[N],bl[N],st[K],ed[K],Pos[2],pos[K<<2][K][2];
11 ll a[N],tag[K<<2],b[K<<2][K];
12 int read(){
13 int x=0,flag=0;
14 char c=getchar();
15 while ((c<'0')||(c>'9')){
16 if (c=='-')flag=1;
17 c=getchar();
18 }
19 while ((c>='0')&&(c<='9')){
20 x=x*10+(c-'0');
21 c=getchar();
22 }
23 if (flag)x=-x;
24 return x;
25 }
26 void write(int x,char c='\0'){
27 while (x){
28 num[++num[0]]=x%10;
29 x/=10;
30 }
31 if (!num[0])putchar('0');
32 while (num[0])putchar(num[num[0]--]+'0');
33 putchar(c);
34 }
35 bool cmp(int x,int y){
36 return a[x]<a[y];
37 }
38 void upd(int k,int l,int r,int x){
39 vector<int>v0,v1;
40 for(int i=l;i<=r;i++)a[i]+=x;
41 for(int i=st[k];i<=ed[k];i++)
42 if ((l<=id[i])&&(id[i]<=r))v0.push_back(id[i]);
43 else v1.push_back(id[i]);
44 for(int i=st[k],x=0,y=0;i<=ed[k];i++){
45 if ((x<v0.size())&&((y==v1.size())||(cmp(v0[x],v1[y]))))id[i]=v0[x++];
46 else id[i]=v1[y++];
47 }
48 }
49 void get(int k,int x){
50 b[k][0]=0;
51 for(int i=st[x];i<=ed[x];i++)b[k][++b[k][0]]=a[id[i]];
52 }
53 void up(int k){
54 b[k][0]=0;
55 int x=1,y=1;
56 while ((x<=b[L][0])||(y<=b[R][0])){
57 if ((x<=b[L][0])&&((y>b[R][0])||(b[L][x]+tag[L]<b[R][y]+tag[R]))){
58 b[k][++b[k][0]]=b[L][x]+tag[L];
59 pos[k][b[k][0]][0]=x;
60 pos[k][b[k][0]][1]=0;
61 x+=D;
62 }
63 else{
64 b[k][++b[k][0]]=b[R][y]+tag[R];
65 pos[k][b[k][0]][0]=0;
66 pos[k][b[k][0]][1]=y;
67 y+=D;
68 }
69 }
70 memset(Pos,0,sizeof(Pos));
71 for(int i=1;i<=b[k][0];i++)
72 for(int p=0;p<2;p++){
73 if (pos[k][i][p])Pos[p]=pos[k][i][p];
74 pos[k][i][p]=Pos[p];
75 }
76 }
77 void build(int k,int l,int r){
78 if (l==r){
79 get(k,l);
80 return;
81 }
82 build(L,l,mid);
83 build(R,mid+1,r);
84 up(k);
85 }
86 void update_point(int k,int l,int r,int x){
87 if (l==r){
88 get(k,x);
89 return;
90 }
91 if (x<=mid)update_point(L,l,mid,x);
92 else update_point(R,mid+1,r,x);
93 up(k);
94 }
95 void update_seg(int k,int l,int r,int x,int y,int z){
96 if ((l>y)||(x>r))return;
97 if ((x<=l)&&(r<=y)){
98 tag[k]+=z;
99 return;
100 }
101 update_seg(L,l,mid,x,y,z);
102 update_seg(R,mid+1,r,x,y,z);
103 up(k);
104 }
105 ll query_tag(int k,int l,int r,int x){
106 if (l==r)return tag[k];
107 if (x<=mid)return query_tag(L,l,mid,x)+tag[k];
108 return query_tag(R,mid+1,r,x)+tag[k];
109 }
110 int query_seg(int k,int l,int r,int x,int y,int z,ll w){
111 if ((l>y)||(x>r)||(!z))return 0;
112 if (l==r)return z;
113 int zl=pos[k][z][0],zr=pos[k][z][1];
114 while ((zl<b[L][0])&&(b[L][zl+1]+tag[L]<w))zl++;
115 while ((zr<b[R][0])&&(b[R][zr+1]+tag[R]<w))zr++;
116 return query_seg(L,l,mid,x,y,zl,w-tag[L])+query_seg(R,mid+1,r,x,y,zr,w-tag[R]);
117 }
118 int query(int l,int r,ll x){
119 int y=upper_bound(b[1]+1,b[1]+b[1][0]+1,x)-b[1]-1;
120 return query_seg(1,1,bl[n],l,r,y,x);
121 }
122 int main(){
123 n=read(),k=(int)sqrt(n);
124 for(int i=1;i<=n;i++)a[i]=read();
125 for(int i=1;i<=n;i++){
126 id[i]=i;
127 bl[i]=(i-1)/k+1;
128 if (!st[bl[i]])st[bl[i]]=i;
129 ed[bl[i]]=i;
130 }
131 for(int i=1;i<=bl[n];i++)sort(id+st[i],id+ed[i]+1,cmp);
132 build(1,1,bl[n]);
133 for(int i=1;i<=n;i++){
134 p=read(),l=read(),r=read(),x=read();
135 if (!p){
136 if (bl[l]==bl[r]){
137 upd(bl[l],l,r,x);
138 update_point(1,1,bl[n],bl[l]);
139 }
140 else{
141 update_seg(1,1,bl[n],bl[l]+1,bl[r]-1,x);
142 upd(bl[l],l,ed[bl[l]],x);
143 update_point(1,1,bl[n],bl[l]);
144 upd(bl[r],st[bl[r]],r,x);
145 update_point(1,1,bl[n],bl[r]);
146 }
147 }
148 else{
149 ans=0;
150 if (bl[l]==bl[r]){
151 ll z=(ll)x*x-query_tag(1,1,bl[n],bl[l]);
152 for(int j=l;j<=r;j++)
153 if (a[j]<z)ans++;
154 }
155 else{
156 ans=query(bl[l]+1,bl[r]-1,(ll)x*x);
157 ll z=(ll)x*x-query_tag(1,1,bl[n],bl[l]);
158 for(int j=l;j<=ed[bl[l]];j++)
159 if (a[j]<z)ans++;
160 z=(ll)x*x-query_tag(1,1,bl[n],bl[r]);
161 for(int j=st[bl[r]];j<=r;j++)
162 if (a[j]<z)ans++;
163 }
164 write(ans,'\n');
165 }
166 }
167 return 0;
168 }
[loj6278]数列分块入门2的更多相关文章
- [LOJ6278]数列分块入门 2
题目大意: 给你一个长度为$n(n\leq 50000)$的序列$A$,支持进行以下两种操作: 1.将区间$[l,r]$中所有数加上$c$: 2.询问区间$[l,r]$中小于$c^2$的数的个数.思路 ...
- 题解——loj6278 数列分块入门2 (分块)
查询小于k的值 注意lower_bound一定要减去查找的起始位置得到正确的位置 调了快两天 淦 #include <cstdio> #include <algorithm> ...
- loj6278 数列分块入门题2
题意:支持区间加,询问区间中元素排名 维护两个域.一个域维护原序列,一个域维护快内排序序列. 每次修改后更新快内排序序列. 修改时O(sqrt(n)log(sqrt(n))) 询问时O(sqrt(n) ...
- LOJ6277~6285 数列分块入门
Portals 分块需注意的问题 数组大小应为,因为最后一个块可能会超出的范围. 当操作的区间在一个块内时,要特判成暴力修改. 要清楚什么时候应该+tag[t] 数列分块入门 1 给出一个长为的数列, ...
- 数列分块入门九题(三):LOJ6283~6285
Preface 最后一题我一直觉得用莫队是最好的. 数列分块入门 7--区间乘法,区间加法,单点询问 还是很简单的吧,比起数列分块入门 7就多了个区间乘. 类似于线段树,由于乘法的优先级高于加法,因此 ...
- 数列分块入门九题(二):LOJ6280~6282
Preface 个人感觉这中间的三题是最水的没有之一 数列分块入门 4--区间加法,区间求和 这个也是很多数据结构完爆的题目线段树入门题,但是练分块我们就要写吗 修改还是与之前类似,只不过我们要维护每 ...
- 数列分块入门九题(一):LOJ6277~6279
Preface 分块,一个神奇的暴力算法.可以把很多\(O(n^2)\)的数据结构题的暴力优化到常数极小的\(O(n\sqrt n)\).当一些毒瘤题无法用线段树,主席树,平衡树,树状数组...... ...
- LOJ6285 数列分块入门9(分块)
昨天对着代码看了一晚上 然后今天终于在loj上过了 数列分块入门9题撒花★,°:.☆( ̄▽ ̄)/$:.°★ . 然后相当玄学 块的大小调成\(\sqrt{n}\)会TLE,改成150就过了 啧 然后就 ...
- LOJ 6277:数列分块入门 1(分块入门)
#6277. 数列分块入门 1 内存限制:256 MiB时间限制:100 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论 3 测试数据 题目描述 给出一 ...
随机推荐
- 重磅 | 阿里开源首个 Serverless 开发者平台 Serverless Devs
Serverless 从概念提出到应用,已经走过了 8 个年头,开发者对 Serverless 的使用热情不断高涨.为帮助开发者实现一键体验多云产品,极速部署 Serverless 项目,10 月 2 ...
- hexo访问优化之--------gulp压缩
hexo访问优化之--------gulp压缩 hexo生成的博客是静态html页面,当有很多静态资源时,加载速度会非常慢,且github服务器在国外,导致网页加载速度非常差 gulp压缩 gulp是 ...
- NOI2018屠龙勇士(扩展CRT + splay(multiset))
QWQ 一到假期就颓废 哎 今年新鲜出炉的NOI题,QwQ同步赛的时候写的,后来交了一发洛谷,竟然过了 首先 根据题目,我们很容易得到,假设对应每一条龙的剑的攻击力是\(atk\)的话 \[a_i-x ...
- Bloom Filter算法
Bloom Filter算法详解 什么是布隆过滤器 布隆过滤器(Bloom Filter)是 1970 年由布隆提出的.它实际上是一个很长的二进制向量和一系列随机映射函数 (下面详细说),实际上你也可 ...
- Protocol handler start failed
问题描述: 启动项目的时候出现的中文大体意思是:协议处理程序启动失败看着这个启动失败,下意识就想是不是端口占用了,结果换个端口还是不行,于是百度了一个办法 问题解决: 打开任务管理器,找到Java的后 ...
- 手摸手教你用 yapi-to-typescript生成Yapi的TypeScript数据类型
一 背景 现代社会比较重视效率,本着这个思想宗旨,能用工具自动高效做的事情,就不要低质量的勤奋.yapi-to-typescript就是一款自动生成接口请求与响应的typescript数据类型定义的工 ...
- 回应:Alpha深度评测
零.说明 本篇博客是针对博客沉舟侧畔千帆过,病树前头万木春--对[题士]产品的深度测评与解析的回应,用以说明『题士』开发团队的观点.改进计划等 感谢HansBug.CookieLau助教及各位老师.测 ...
- (数据科学学习手札129)geopandas 0.10版本重要新特性一览
本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 就在前不久,我们非常熟悉的Python地理 ...
- Noip模拟81 2021.10.20
T1 语言 比较简单的题,然后就瞎写了,所以考场上就我一个写了线段树的,所以我的常数.... 所以就枚举动词的位置,找前面后面有没有出现$4$即可 1 #include<bits/stdc++. ...
- Noip模拟73 2021.10.10
老妈送来了防寒补给就很棒,再也不用晚上盖两层毛巾被了,再也不用担心晚上自动把毛巾被$split$了 还有一些好吃的耶叶 T1 小L的疑惑 考场上疑惑的切掉了 直接把$a$排序然后处理前缀和的过程中判断 ...