分块笔记
分块
分块1
单点查值,区间加值
#include <iostream>
#include <cmath>
using namespace std;
#define int long long
const int N = 5e4+10,M = 1000;
int a[N],n,m,ed[M],st[M],belong[N],add[M];
inline int read(){
int res = 0, flag = 1;
char ch = getchar();
while(ch < '0'|| ch > '9'){
if(ch == '-')flag = -1;
ch = getchar();
}
while(ch >= '0'&& ch <= '9'){
res = (res<<1) + (res<<3) + (ch^48);
ch = getchar();
}
return res * flag;
}
void build(int n)
{
int num = sqrt(n);
for(int i = 1 ; i <= num ; i ++ )
{
st[i] = n / num * (i - 1) + 1;
ed[i] = n / num * i;
}
ed[num] = n;
for(int i = 1 ; i <= num ; i ++ )
for(int j = st[i] ; j <= ed[i] ; j ++ )
belong[j] = i;
}
void change(int l,int r,int c)
{
int x = belong[l],y = belong[r];
if(x == y)
{
for(int i = l;i <= r;i++)a[i] += c;
return;
}
for(int i = l ; i <= ed[x] ; i ++ )a[i] += c;
for(int i = st[y] ; i <= r ; i ++)a[i] += c;
for(int i = x + 1 ; i <= y - 1; i ++ )add[i] += c;
}
int ask(int r)
{
int x = belong[r];
return a[r] + add[x];
}
signed main()
{
//freopen("a1.in","r",stdin);
//freopen("a_2.out","w",stdout);
n = read();
for(int i = 1 ; i <= n ; i ++ )a[i] = read();
build(n);
for(int opt,l,r,c,i = 1 ; i <= n ; i ++ )
{
opt = read();
l = read();
r = read();
c = read();
if(opt){
printf("%lld\n",ask(r));
}
else {
change(l,r,c);
}
}
}
分块二
给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的元素个数。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define IOin(x) freopen(#x,"r",stdin)
#define IOout(x) freopen(#x,"w",stdout)
#define int long long
const int N = 5e4 + 10,M =1e3;
int n,a[N],belong[N],st[M],ed[M],add[M],num;
inline int read(){
int res = 0, flag = 1;
char ch = getchar();
while(ch < '0'|| ch > '9'){
if(ch == '-')flag = -1;
ch = getchar();
}
while(ch >= '0'&& ch <= '9'){
res = (res<<1) + (res<<3) + (ch^48);
ch = getchar();
}
return res * flag;
}
void build(int n)
{
num = sqrt(n);
for(int i = 1 ; i <= num ; i ++ )
{
st[i] = n / num * (i - 1) + 1;
ed[i] = n / num * i ;
}
ed[num] = n;
for(int i = 1 ; i <= num ; i ++ )
{
for(int j = st[i] ; j <= ed[i] ; j ++ )
belong[j] = i;
}
}
void change(int l,int r,int c)
{
int x = belong[l],y = belong[r];
if(x == y)
{
for(int i = l ; i <= r ; i ++ )a[i] += c;
return ;
}
for(int i = l ; i <= ed[x] ; i ++ )a[i] += c;
for(int i = st[y] ; i <= r ; i ++ )a[i] += c;
for(int i = x + 1 ; i <= y - 1 ; i ++ )add[i] += c;
}
int ask(int l,int r,int c)
{
int cnt = 0;
int x = belong[l],y = belong[r];
if(x == y)
{
for(int i = l ; i <= r ; i ++ )
if(a[i] + add[x] < c)cnt ++ ;
return cnt;
}
for(int i = l ; i <= ed[x] ; i ++ )
if(a[i] + add[x] < c)cnt ++ ;
for(int i = st[y] ; i <= r ; i ++ )
if(a[i] + add[y] < c)cnt ++ ;
for(int i = x + 1 ; i <= y - 1 ; i ++ )
{
for(int j = st[i] ; j <= ed[i] ; j ++ )
if(a[j] + add[i] < c)cnt ++ ;
}
return cnt;
}
signed main()
{
//IOin(a1.in);
//IOout(a11.out);
n = read();
for(int i = 1 ; i <= n ; i ++ ) a[i] = read();
build(n);
for(int i = 1 ; i <= n ; i ++ )
{
int opt,l,r,c;
opt = read();
l = read();
r = read();
c = read();
if(!opt){
change(l,r,c);
}else {
printf("%d\n",ask(l,r,c*c));
}
}
}
分块3
给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的前驱(比其小的最大元素)。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
const int N = 1e6 + 10 , M = 1e3 + 10;
int a[N],llt[N],b[N],n,len;
set<int>s[M];
inline int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
res = (res<<1) + (res << 3) + (ch^48);
ch = getchar();
}
return res * flag ;
}
void add(int l,int r,int c)
{
int x = llt[l] , y = llt[r];
for (int i = l ; i <= min(x * len , r) ; i ++ )
{
s[x].erase(a[i]);
a[i] += c;
s[x].insert(a[i]);
}
if(x != y)
{
for (int i = len * (y - 1) + 1 ; i <= r ; i ++ )
{
s[y].erase(a[i]);
a[i] += c;
s[y].insert(a[i]);
}
}
for (int i = x + 1 ; i <= y - 1 ; i ++ )
b[i] += c;
}
void ask(int l,int r,int c)
{
int ans = - 1;
int x = llt[l], y = llt[r];
for (int i = l ; i <= min(x * len , r) ; i ++ )
if(a[i] + b[x] < c)
ans = max(ans, a[i] + b[x]);
if(x != y)
{
for (int i = len * (y - 1) + 1 ; i <= r ; i ++ )
if(a[i] + b[y] < c)
ans = max(ans , a[i] + b[y]);
}
for (int i = x + 1 ; i <= y - 1 ; i ++ )
{
int t = c - b[i] ;
set<int>::iterator it = s[i].lower_bound(t);
if(it == s[i].begin()) continue;
it -- ;
ans = max(ans , *it + b[i]);
}
printf("%d\n",ans);
}
int main()
{
n = read();
len = 1000 ;
for (int i = 1 ; i <= n ; i ++ )
a[i] = read(),
llt[i] = (i - 1) / len + 1,
s[llt[i]].insert(a[i]);
for (int i = 1 ; i <= n ; i ++ )
{
int opt , l , r , c;
opt = read();
l = read();
r = read();
c = read();
if(opt == 1)
ask(l,r,c);
else
add(l,r,c);
}
return 0;
}
“风雪越是呼啸,雪莲越是绽放”