链接:数列分块入门
数列分块入门1:
题意:区间更新,单点查询
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 50010;
int num, block;
int l[mx], r[mx];
int belong[mx];
int a[mx];
int add[mx];
void build(int n){
block = sqrt(n);
num = n / block;
if(n % block)num++;
for(int i = 1; i <= num; i++){
l[i] = (i - 1)*block + 1;
r[i] = i * block;
}
r[num] = n;
for(int i = 1; i <= n; i++){
belong[i] = (i - 1)/block + 1;
}
}
void update(int x, int y, int c){
if(belong[x] == belong[y]){
for(int i = x; i <= y; i++){
a[i] += c;
}
return;
}
for(int i = x; i <= r[belong[x]]; i++){
a[i] += c;
}
for(int i = belong[x] + 1; i < belong[y]; i++){
add[i] += c;
}
for(int i = l[belong[y]]; i <= y; i++){
a[i] += c;
}
}
int main(){
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
add[i] = 0;
}
build(n);
int q = n;
while(q--){
int op, x, y, c;
scanf("%d %d %d %d", &op, &x, &y, &c);
if(op == 0){
update(x, y, c);
}
else{
printf("%d\n", a[y] + add[belong[y]]);
}
}
return 0;
}
数列分块入门2:
题意:区间修改,查询区间中小于某个数平方的个数
思路:vector维护,排序,二分
代码:
#include<bits/stdc++.h>
using namespace std;
const int mx = 50010;
int n;
int num, block;
int a[mx], mark[mx], l[mx], r[mx], belong[mx];
vector<int> v[510];
void build(){
block = sqrt(n);
num = n / block;
if(n % block)num++;
for(int i = 1; i <= num; i++){
l[i] = (i - 1)*block + 1;
r[i] = i * block;
}
r[num] = n;
for(int i = 1; i <= n; i++){
belong[i] = (i - 1)/block + 1;
v[belong[i]].push_back(a[i]);
}
for(int i = 1; i <= belong[n]; i++){
sort(v[i].begin(), v[i].end());
}
}
void update(int x){
v[x].clear();
for(int i = (x - 1) * block + 1; i <= min(x * block, n); i++){
v[x].push_back(a[i]);
}
sort(v[x].begin(), v[x].end());
}
void add(int x, int y, int c){
//printf("111111111\n");
for(int i = x; i <= min(belong[x] * block, y); i++){
a[i] += c;
}
update(belong[x]);
if(belong[x] != belong[y]){
for(int i = (belong[y] - 1) * block + 1; i <= y; i++){
a[i] += c;
}
update(belong[y]);
}
for(int i = belong[x] + 1; i < belong[y]; i++){
mark[i] += c;
}
}
int query(int x, int y, int c){
int ans = 0;
for(int i = x; i <= min(belong[x] * block, y); i++){
if(a[i] + mark[belong[x]] < c)ans++;
}
if(belong[x] != belong[y]){
for(int i = (belong[y] - 1) * block + 1; i <= y; i++){
if(a[i] + mark[belong[y]] < c)ans++;
}
}
for(int i = belong[x] + 1; i < belong[y]; i++){
int cc = c - mark[i];
ans += lower_bound(v[i].begin(), v[i].end(), cc) - v[i].begin();
}
return ans;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
mark[i] = 0;
}
build();
int op, x, y, c;
int q = n;
while(q--){
scanf("%d %d %d %d", &op, &x, &y, &c);
if(op == 0){
add(x, y, c);
}
else{
printf("%d\n", query(x, y ,c * c));
}
}
return 0;
}
数列分块入门3:
题意:区间更新,查询区间内c的前驱(小于某个数的最大数)
思路:和入门2差不多,用vector维护,排序二分,(自己手写了一个二分T了)--
找了题解用set维护,然后二分
vector代码:(留坑回头补)
set代码:
#include<bits/stdc++.h>
using namespace std;
const int mx = 110010;
const int INF = 0x3f3f3f3f;
int a[mx], mark[mx], l[mx], r[mx], belong[mx];
int block, num;
int n;
set<int> s[1100];
void build(){
block = sqrt(n);
num = n / block;
if(n % block)num++;
for(int i = 1; i <= num; i++){
l[i] = (i - 1)*block + 1;
r[i] = i * block;
}
r[num] = n;
for(int i = 1; i <= n; i++){
belong[i] = (i - 1)/block + 1;
s[belong[i]].insert(a[i]);
}
}
void add(int x, int y, int c){
for(int i = x; i <= min(belong[x]*block, y); i++){
s[belong[i]].erase(a[i]);
a[i] += c;
s[belong[i]].insert(a[i]);
}
if(belong[x] != belong[y]){
for(int i = (belong[y] - 1)*block + 1; i <= y; i++){
s[belong[i]].erase(a[i]);
a[i] += c;
s[belong[i]].insert(a[i]);
}
}
for(int i = belong[x] + 1; i < belong[y]; i++){
mark[i] += c;
}
}
int query(int x, int y, int c){
int ans = -INF;
for(int i = x; i <= min(belong[x]*block, y); i++){
if(a[i] + mark[belong[i]] < c){
ans = max(ans, a[i] + mark[belong[i]]);
}
}
if(belong[x] != belong[y]){
for(int i = (belong[y] - 1)*block + 1; i <= y; i++){
if(a[i] + mark[belong[i]] < c){
ans = max(ans, a[i] + mark[belong[i]]);
}
}
}
for(int i = belong[x] + 1; i < belong[y]; i++){
int cc = c - mark[i];
set<int>::iterator it = s[i].lower_bound(cc);
if(it == s[i].begin())continue;
it--;
ans = max(ans, *it + mark[i]);
}
if(ans == -INF)ans = -1;
return ans;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
mark[i] = 0;
}
build();
int q = n;
while(q--){
int op, x, y, c;
scanf("%d %d %d %d", &op, &x, &y, &c);
if(op == 0){
add(x, y, c);
}
else{
printf("%d\n", query(x, y, c));
}
}
return 0;
}
数列分块入门4:
题意:区间更新,区间求和,mod c+1
思路:开个数组记录每个分块的和,和区间一起更新,查询的时候加回来
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 500100;
ll belong[mx], a[mx], mark[mx];
ll num, block, n;
ll sum[mx];
void build(){
block = sqrt(n);
num = n / block;
if(n % block)num++;
for(int i = 1; i <= n; i++){
belong[i] = (i - 1)/block + 1;
}
for(ll i = 1; i <= n; i++){
sum[belong[i]] += a[i];
}
}
void add(ll x, ll y, ll c){
for(ll i = x; i <= min(belong[x]*block, y); i++){
a[i] += c, sum[belong[i]] += c;
}
if(belong[x] != belong[y]){
for(ll i = (belong[y] - 1)*block+1; i <= y; i++){
a[i] += c, sum[belong[i]] += c;
}
}
for(ll i = belong[x] + 1; i < belong[y]; i++){
mark[i] += c;
}
}
ll query(ll x, ll y, ll c){
c++;
ll ans = 0;
for(ll i = x; i <= min(belong[x]*block, y); i++){
ans += a[i] + mark[belong[i]];
}
if(belong[x] != belong[y]){
for(ll i = (belong[y] - 1)*block + 1; i <= y; i++){
ans += a[i] + mark[belong[i]];
}
}
for(ll i = belong[x] + 1; i < belong[y]; i++){
ans += mark[i] * block + sum[i];
}
//ans = (ans % c + c) % c;
return ans % c;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%lld", &a[i]);
mark[i] = 0;
sum[i] = 0;
}
build();
int q = n;
while(q--){
ll op, x, y, c;
scanf("%lld %lld %lld %lld", &op, &x, &y, &c);
if(op == 0){
add(x, y, c);
/*for(int i = 1; i <= n; i++){
printf("%d%c", a[i], i == n ? '\n' : ' ');
}
for(int i = 1; i <= num; i++){
printf("%d%c", mark[i], i == num ? '\n' : ' ');
}*/
}
else{
printf("%lld\n", query(x, y, c));
}
}
return 0;
}
数列分块入门5
题意:区间修改(分别开根号),区间求和
分析:刚看到这题,觉得分块做不了,每次修改整块区间都要去访问每个元素去开根号,这样分块压根就没有意义,后来一想,int内的数,在4-5次内开根号就能变成0或1(每次开完后,都向下取整),这样,只要用个数组标记下,这整块区间是否都为0/1,当标记成功后,这个区间可以直接不操作。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mx = 1e5 + 10;
int n, block, num;
int belong[mx], a[mx], mark[mx], sum[mx];
void build(){
block = sqrt(n);
num = n / block;
if(n % block)num++;
for(int i = 1; i <= n; i++){
belong[i] = (i - 1)/block + 1;
}
for(int i = 1; i <= n; i++){
sum[belong[i]] += a[i];
}
}
void update(int x){
sum[belong[x]] -= a[x];
a[x] = sqrt(a[x]);
sum[belong[x]] += a[x];
}
void update1(int x){
if(mark[x])return;
mark[x] = 1;
sum[x] = 0;
for(int i = (x - 1)*block + 1; i <= x*block; i++){
a[i] = sqrt(a[i]);
sum[x] += a[i];
if(a[i] > 1)mark[x] = 0;
}
}
void sq(int l, int r, int c){
for(int i = l; i <= min(belong[l]*block, r); i++){
update(i);
/*sum[belong[l]] -= a[i];
a[i] = sqrt(a[i]);
sum[belong[l]] += a[i];*/
}
if(belong[l] != belong[r]){
for(int i = (belong[r] - 1)*block + 1; i <= r; i++){
update(i);
/*sum[belong[r]] -= a[i];
a[i] = sqrt(a[i]);
sum[belong[r]] += a[i];*/
}
}
for(int i = belong[l] + 1; i < belong[r]; i++){
update1(i);
}
}
int query(int l, int r){
int ans = 0;
for(int i = l; i <= min(belong[l]*block, r); i++){
ans += a[i];
}
if(belong[l] != belong[r]){
for(int i = (belong[r] - 1)*block + 1; i <= r; i++){
ans += a[i];
}
}
for(int i = belong[l] + 1; i < belong[r]; i++){
ans += sum[i];
}
return ans;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
mark[i] = 0;
sum[i] = 0;
}
build();
int q = n;
while(q--){
int op, l, r, c;
scanf("%d %d %d %d", &op, &l, &r, &c);
if(op == 0){
sq(l, r, c);
}
else{
printf("%d\n", query(l, r));
}
}
return 0;
}