题目描述
当然,您想想,耳机里除了沙沙声什么也没有,屏幕上一片空白,对作战命令和周围的战场态势一无所知,可不就是这种感觉嘛!这黑暗,压得人喘不过气来啊。 ——《全频段阻塞干扰》
你深知战场上情报优势不在自己的黑暗,于是早已提前制作了一个工具从机房的网络交换机上获取网络情报,它可以实时获取机房里每个人进行机惨的几率,精确到0.1%。你已经使用了空间压缩技术把机房战场转化成了一条序列,序列上的元素表示这个人进行机惨的几率,现在你想知道某一片战场的平静程度,即这个序列中区间[l,r]里有多少个人的机惨几率不大于某个数。同时因为是实时战场数据,每个人机惨的几率是会变化的,即会若干次修改一个人的几率。
简化题意:给定一个序列,每次求区间小于某数的数的个数,或把一个数改成另一个数。
输入
第一行两个数 n,m,表示机房地形转化成序列后的长度和操作个数。
第二行 n 个整数 pi ,表示位置为 i 的人机惨的概率为pi/1000。
接下来 m 行每行第一个为整数op,若op为1则后面有两个整数x,y,表示把x位置上的概率改成y/1000,为2则后面有三个整数l,r,y表示查询区间 [l,r] 里概率小于 y/1000的有几个位置。
输出
对每个op为2的询问输出一行一个整数表示答案。
样例
样例输入
10 10
4 8 4 7 8 8 7 2 1 8
1 1 4
1 10 3
1 7 8
2 6 7 4
2 5 9 3
1 2 1
2 1 9 4
1 5 4
2 2 5 7
2 6 7 3
样例输出
0
2
3
3
0
提示
对10%的数据保证n ≤1e3, m ≤1e3。
对另外20%的数据保证op=2。
对100%的数据保证n ≤1e5, m ≤1e4, p,y≤1e3, x,l,r∈[1,n]。
分析
分块、块状数组
块状数组
即把一个数组分为几个块,块内信息整体保存,
对于一次区间操作,对区间內部的整块进行整体的操作,对区间边缘的零散块单独暴力处理。
一般分为sqrt(n)个块,
总时间复杂度为sqrt(n)
将序列分成sqrt(n) 块,用 vector 存储每一块里的元素并排序。
若操作为修改,则将对应块的元素更改后重新排序;
若操作为查询,对于被完全覆盖的块,直接二分,零散块则直接暴力
实现
sq为分成的块的数量,
st表示第i个块的第一个元素的下标,ed表示第i个块最后一个元素的下标,
bel[j] = i
表示第j个元素属于第i个块
void init(){
int sq = sqrt(n);
for(int i = 1;i <= sq;i++){
st[i] = n / sq * (i - 1) + 1;
ed[i] = n / sq * i;
}
ed[sq] = n;
for(int i = 1;i <= sq;i++)
for(int j = st[i];j <= ed[i];j++){
bel[j] = i;
s[i].push_back(a[j]);
}
for(int i = 1;i <= sq;i++) sort(s[i].begin(),s[i].end());
}
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n,m;
int a[N];
int st[N],ed[N],bel[N];
vector<int> s[N];
void init(){
int sq = sqrt(n);
for(int i = 1;i <= sq;i++){
st[i] = n / sq * (i - 1) + 1;
ed[i] = n / sq * i;
}
ed[sq] = n;
for(int i = 1;i <= sq;i++)
for(int j = st[i];j <= ed[i];j++){
bel[j] = i;
s[i].push_back(a[j]);
}
for(int i = 1;i <= sq;i++) sort(s[i].begin(),s[i].end());
}
void modify(int k,int x){
int pos = bel[k];
*lower_bound(s[pos].begin(),s[pos].end(),a[k]) = x;
a[k] = x;
sort(s[pos].begin(),s[pos].end());
}
int query(int l,int r,int x){
int cnt = 0;
if(bel[l] == bel[r]){
for(int i = l;i <= r;i++)
if(a[i] < x) cnt++;
}else{
for(int i = l;i <= ed[bel[l]];i++)
if(a[i] < x) cnt++;
for(int i = bel[l] + 1;i <= bel[r] - 1;i++)
cnt += lower_bound(s[i].begin(),s[i].end(),x) - s[i].begin();
for(int i = st[bel[r]];i <= r;i++)
if(a[i] < x) cnt++;
}
return cnt;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= n;i++) cin >> a[i];
init();
int op,l,r,x,y;
while(m--){
cin >> op;
if(op == 1){
cin >> x >> y;
modify(x,y);
}else{
cin >> l >> r >> y;
cout << query(l,r,y) << '\n';
}
}
return 0;
}