分块算法的基本思想是通过适当的划分,预处理一部分的信息并保存下来,用空间换取时间,达到时空平衡。
分块1
给定长度为N的数列A,然后输入M行操作指令。
第一类指令形如“C l r d”,表示把数列中第l~r个数都加d。
第二类指令形如“Q X”,表示询问数列中第x个数的值。
对于每个询问,输出一个整数表示答案。
区间修改,单点查询
ll sum[N];
int pos[N];
ll add[N];
ll a[N];
int L[N];
int R[N];
ll query(int id){
int p = pos[id];
return a[id] + add[p];
}
void Add(int l,int r,ll d){
if(l > r) swap(l,r);
int p1 = pos[l],p2 = pos[r];
if(p1 == p2){
for(int i = l;i <= r;++i) a[i] += d;
sum[p1] += 1LL*(r - l + 1) * d;
return ;
}
for(int i = l;i <= R[p1];++i) a[i] += d;
sum[p1] += 1LL*(R[p1] - l + 1) * d;
for(int i = L[p2];i <= r;++i) a[i] += d;
sum[p2] += 1LL*(r - L[p2] + 1)*d;
for(int i = p1+1;i <= p2- 1;++i) sum[i] += 1LL*(R[i] - L[i] + 1)*d,add[i] += d;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i) scanf("%lld",&a[i]);
//分块
int t = sqrt(n);
for(int i = 1;i <= t;++i){
L[i] = (i-1)*t + 1;
R[i] = i*t;
}
if(R[t] < n) t++,L[t] = R[t-1] + 1,R[t] = n;
for(int i = 1;i <= t;++i){
for(int j = L[i];j <= R[i];++j){
pos[j] = i;
sum[i] += a[j];
}
}
for(int i = 1;i <= m;++i){
char c;
scanf("%s",&c);
if(c == 'Q'){
int b;
scanf("%d",&b);
printf("%lld\n",query(b));
}
else {
int l,r;ll d;
scanf("%d%d%lld",&l,&r,&d);
Add(l,r,d);
}
}
}
分块2
给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
2、“Q l r”,表示询问 数列中第 l~r 个数的和。
对于每个询问,输出一个整数表示答案。
区间修改,区间查询
ll add[500];
ll pos[N];
ll sum[500];
ll a[N];
int L[500],R[500];
ll query(int l,int r){
if(l > r) swap(l,r);
int p1 = pos[l],p2 = pos[r];
ll ans = 0;
if(p1 == p2){
for(int i = l;i <= r;++i){
ans += a[i];
}
return ans + (r - l + 1) * add[p1];
}
for(int i = l;i <= R[p1];++i) ans += a[i];
ans += 1LL*(R[p1] - l + 1) * add[p1];
for(int i = L[p2];i <= r;++i) ans += a[i];
ans += 1LL*(r - L[p2] + 1) * add[p2];
for(int i = p1 + 1;i <= p2-1;++i) ans += sum[i] + (R[i] - L[i] + 1)*add[i];
return ans;
}
void Add(int l,int r,int d){
if(l > r) swap(l,r);
int p1 = pos[l],p2 = pos[r];
if(p1 == p2){
for(int i = l;i <= r;++i) a[i] += d;
sum[p1] += 1LL*(r - l + 1) * d;
return ;
}
for(int i = l;i <= R[p1];++i) a[i] += d;
sum[p1] += 1LL*(R[p1] - l + 1) * d;
for(int i = L[p2];i<= r;++i) a[i] += d;
sum[p2] += 1LL*(r - L[p2] + 1) * d;
for(int i = p1+1;i<=p2-1;++i) add[i] += d;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i) scanf("%lld",&a[i]);
int t = sqrt(n);
for(int i = 1;i <= t;++i){
L[i] = (i-1)*t + 1;
R[i] = i*t;
}
if(R[t] < n) t++,L[t] = R[t-1] + 1,R[t] = n;
for(int i = 1;i <= t;++i){
for(int j = L[i];j <= R[i];++j){
pos[j] = i;
sum[i] += a[j];
}
}
char Q;int l,r,d;
for(int i = 1;i <= m;++i){
scanf("%s",&Q);
if(Q == 'Q'){
scanf("%d%d",&l,&r);
printf("%lld\n",query(l,r));
}
else {
scanf("%d%d%d",&l,&r,&d);
Add(l,r,d);
}
}
}
数列分块入门系列
1、
int L[500],R[500];
ll a[N];
int pos[N];
ll add[500];
void divided(int n){
int t = sqrt(n);
for(int i = 1;i <= t;++i) L[i] = (i - 1)*t + 1,R[i] = i*t;
if(R[t] < n) t++,L[t] = R[t-1] + 1,R[t] = n;
for(int i = 1;i <= t;++i){
for(int j = L[i];j <= R[i];++j) pos[j] = i;
}
}
void Add(int l,int r,int d){
int p = pos[l],q = pos[r];
if(p == q){
for(int i = l;i <= r;++i) a[i] += d;
}
else {
for(int i = l;i <= R[p];++i) a[i] += d;
for(int i = L[q];i <= r;++i) a[i] += d;
for(int i = p+1;i<=q-1;++i) add[i] += d;
}
}
ll query(int x){
int p = pos[x];
return a[x] + add[p];
}
int main(){
int n,l,r,d;
int op;
scanf("%d",&n);
for(int i = 1;i <= n;++i) scanf("%lld",&a[i]);
divided(n);
for(int i = 1; i <= n;++i){
scanf("%d%d%d%d",&op,&l,&r,&d);
if(!op) Add(l,r,d);
else printf("%lld\n",query(r));
}
}
2、
int L[500],R[500];
ll a[N];
int pos[N];
ll add[500];
vector<int> Q[500];
void divided(int n){
int t = sqrt(n);
for(int i = 1;i <= t;++i) L[i] = (i - 1)*t + 1,R[i] = i*t;
if(R[t] < n) t++,L[t] = R[t-1] + 1,R[t] = n;
for(int i = 1;i <= t;++i){
for(int j = L[i];j <= R[i];++j) pos[j] = i,Q[i].push_back(a[j]);
sort(Q[i].begin(),Q[i].end());
}
}
void Add(int l,int r,int d){
int p = pos[l],q = pos[r];
if(p == q){
for(int i = l;i <= r;++i) a[i] += d;
Q[p].clear();
for(int i = L[p];i <= R[p];++ i) Q[p].push_back(a[i]);
sort(Q[p].begin(),Q[p].end());
}
else {
for(int i = l;i <= R[p];++i) a[i] += d;
Q[p].clear();
for(int i = L[p];i <= R[p];++ i) Q[p].push_back(a[i]);
sort(Q[p].begin(),Q[p].end());
for(int i = L[q];i <= r;++i) a[i] += d;
Q[q].clear();
for(int i = L[q];i <= R[q];++ i) Q[q].push_back(a[i]);
sort(Q[q].begin(),Q[q].end());
for(int i = p+1;i<=q-1;++i) add[i] += d;
}
}
ll query(int l,int r,ll d){
int p = pos[l],q = pos[r];
ll ans = 0;
if(p == q){
for(int i = l;i <= r;++i) if(a[i] + add[p] < d) ans ++;
return ans;
}
for(int i = l;i <= R[p];++i) if(a[i] + add[p]<d) ans ++;
for(int i = L[q];i <= r;++i) if(a[i] + add[q] < d) ans ++;
for(int i = p +1 ;i <= q - 1;++i){
int S = Q[i].size();
int l1 = -1,r1 = S -1;
while(l1 < r1){
int mid = l1 + r1 + 1>> 1;
if(Q[i][mid] >= d-add[i]) r1 = mid - 1;
else l1 =mid;
}
if(l1 != -1) ans += l1 + 1;
}
return ans;
}
int main(){
int n,l,r;ll d;
int op;
scanf("%d",&n);
for(int i = 1;i <= n;++i) scanf("%lld",&a[i]);
divided(n);
for(int i = 1; i <= n;++i){
scanf("%d%d%d%lld",&op,&l,&r,&d);
if(!op) Add(l,r,d);
else printf("%lld\n",query(l,r,d*d));
}
}
3、
ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int L[1000],R[1000];
ll a[N];
int pos[N];
ll add[1000];
vector<ll> Q[1000];
void divided(int n){
int t = sqrt(n);
for(int i = 1;i <= t;++i) L[i] = (i - 1)*t + 1,R[i] = i*t;
if(R[t] < n) t++,L[t] = R[t-1] + 1,R[t] = n;
for(int i = 1;i <= t;++i){
for(int j = L[i];j <= R[i];++j) pos[j] = i,Q[i].push_back(a[j]);
sort(Q[i].begin(),Q[i].end());
}
}
void Add(int l,int r,int d){
int p = pos[l],q = pos[r];
if(p == q){
for(int i = l;i <= r;++i) a[i] += d;
Q[p].clear();
for(int i = L[p];i <= R[p];++ i) Q[p].push_back(a[i]);
sort(Q[p].begin(),Q[p].end());
}
else {
for(int i = l;i <= R[p];++i) a[i] += d;
Q[p].clear();
for(int i = L[p];i <= R[p];++ i) Q[p].push_back(a[i]);
sort(Q[p].begin(),Q[p].end());
for(int i =L[q];i <= r;++i) a[i] += d;
Q[q].clear();
for(int i = L[q];i <= R[q];++ i) Q[q].push_back(a[i]);
sort(Q[q].begin(),Q[q].end());
for(int i = p+1;i<=q-1;++i) add[i] += d;
}
}
ll query(int l,int r,ll d){
int p = pos[l],q = pos[r];
ll ans = -1e11;
if(p == q){
for(int i = l;i <= r;++i) if(a[i] + add[p] < d) ans = max(ans,a[i] +add[p]);
if(ans <= -1e10) return -1;
else return ans;
}
for(int i = l;i <= R[p];++i) if(a[i] + add[p]<d) ans = max(ans,a[i] +add[p]);
for(int i = L[q];i <= r;++i) if(a[i] + add[q] < d) ans = max(ans,a[i] +add[q]);
for(int i = p +1 ;i <= q - 1;++i){
int S = Q[i].size();
int l1 = -1,r1 = S -1;
while(l1 < r1){
int mid = l1 + r1 + 1>> 1;
if(Q[i][mid] >= d-add[i]) r1 = mid - 1;
else l1 =mid;
}
if(l1 != -1) ans = max(ans,Q[i][l1] +add[i]);
}
if(ans <= -1e10) return -1;
else return ans;
}
int main(){
int n,l,r;ll d;
int op;
scanf("%d",&n);
for(int i = 1;i <= n;++i) a[i] = read();
divided(n);
for(int i = 1; i <= n;++i){
op= read();l=read();r=read();d = read();
if(!op) Add(l,r,d);
else printf("%lld\n",query(l,r,d));
}
}
4、
ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int L[1000],R[1000];
ll a[N];
int pos[N];
ll add[1000];
ll sum[1000];
vector<ll> Q[1000];
void divided(int n){
int t = sqrt(n);
for(int i = 1;i <= t;++i) L[i] = (i - 1)*t + 1,R[i] = i*t;
if(R[t] < n) t++,L[t] = R[t-1] + 1,R[t] = n;
for(int i = 1;i <= t;++i){
for(int j = L[i];j <= R[i];++j) pos[j] = i,sum[i] += a[j];
}
}
void Add(int l,int r,ll d){
if(l > r) swap(l,r);
int p = pos[l],q = pos[r];
if(p == q) {
for(int i = l;i <= r;++i) a[i] += d;
sum[p] += (r - l + 1) * d;
return ;
}
for(int i = l;i <= R[p];++i) a[i] += d;
sum[p] += (R[p] - l + 1) * d;
for(int i = L[q];i <= r;++i) a[i] += d;
sum[q] += (r - L[q]+ 1)*d;
for(int i = p + 1;i <= q - 1;++i) add[i] += d;
}
ll query(int l,int r,ll mod){
if(l > r) swap(l,r);
int p = pos[l],q = pos[r];
ll ans= 0;
if(p == q){
for(int i = l;i <= r;++i) ans = (ans + a[i]+add[p]) % mod;
return ans;
}
for(int i = l;i <= R[p];++i) ans = (ans + a[i] + add[p]) % mod;
for(int i = L[q];i <= r;++i) ans = (ans + a[i] + add[q]) % mod;
for(int i = p + 1;i <= q - 1;++i) ans = (ans + sum[i] + add[i]*(R[i] - L[i]+1))% mod;
return ans;
}
int main(){
int n,l,r;ll d;
int op;
scanf("%d",&n);
for(int i = 1;i <= n;++i) a[i] = read();
divided(n);
for(int i = 1; i <= n;++i){
op= read();l=read();r=read();d = read();
if(!op) Add(l,r,d);
else printf("%lld\n",query(l,r,d+1));
}
}
7、
ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int L[1000],R[1000];
ll a[N];
int pos[N];
ll add[1000];
ll mul[1000];
void divided(int n){
int t = sqrt(n);
for(int i = 1;i <= t;++i) L[i] = (i - 1)*t + 1,R[i] = i*t;
if(R[t] < n) t++,L[t] = R[t-1] + 1,R[t] = n;
for(int i = 1;i <= t;++i){
for(int j = L[i];j <= R[i];++j) pos[j] = i,mul[i] = 1;
}
}
void Add(int l,int r,ll d){
if(l > r) swap(l,r);
int p = pos[l],q = pos[r];
if(p == q) {
for(int i = L[p];i <= R[p];++ i) a[i] = (a[i] * mul[p]) % mod;
mul[p] = 1;
for(int i = l;i <= r;++i) a[i] = (a[i] + d) % mod;
return ;
}
for(int i = L[p];i <= R[p];++i) a[i] = (a[i] * mul[p]) % mod;
mul[p] = 1;
for(int i = l;i <= R[p];++i) a[i] = (a[i] + d) % mod;
for(int i = L[q];i <= R[q];++i) a[i] = (a[i] * mul[q]) % mod;
mul[q] = 1;
for(int i = L[q];i <= r;++i) a[i] = (a[i] + d) % mod;
for(int i = p + 1;i <= q - 1;++i) add[i] += d;
}
void Mul(int l,int r,ll d){
int p = pos[l],q = pos[r];
if(p == q){
for(int i = L[p];i <= R[p];++i) a[i] = (a[i]*mul[p]) % mod,a[i] = (a[i] + add[p])%mod;
mul[p] = 1;add[p] = 0;
for(int i = l;i <= r;++i) a[i] = (a[i] * d) % mod;
return ;
}
for(int i = L[p];i <= R[p];++i) a[i] = (a[i]*mul[p]) % mod,a[i] = (a[i] + add[p])%mod;
mul[p] = 1;add[p] = 0;
for(int i = l;i <= R[p];++i) a[i] = (a[i] * d) % mod;
for(int i = L[q];i <= R[q];++i) a[i] = (a[i]*mul[q]) % mod,a[i] = (a[i] + add[q])%mod;
mul[q] = 1;add[q] = 0;
for(int i = L[q];i <= r;++i) a[i] = (a[i] * d) % mod;
for(int i = p + 1;i <= q - 1;++i) mul[i] = (mul[i] * d) % mod,add[i] = (add[i] * d)%mod;
}
ll query(int x){
int p = pos[x];
return mul[p] * a[x] + add[p];
}
int main(){
int n,l,r;ll d;
int op;
scanf("%d",&n);
for(int i = 1;i <= n;++i) a[i] = read();
divided(n);//分块
for(int i = 1; i <= n;++i){
op= read();l=read();r=read();d = read();
if(!op) Add(l,r,d);
else if(op == 1) Mul(l,r,d);
else printf("%lld\n",query(r)%mod);
}
}
其他题目
Codeforces Round #622 (Div. 2)C2. Skyscrapers (hard version)
const int N = 5e5 + 10;
const double eps = 0.00000001;
const ll mod = 1e9 + 7 ;
using namespace std;
ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll a[N];
int L[1000],R[1000];
ll Min[1000];
int pos[N];
ll b[N];
int Find(int l,int r){
int p = pos[l],q = pos[r];
if(p == q){
int M = INF,po = l;
for(int i = l;i <= r;++i) if(M > a[i]) M = a[i],po = i;
return po;
}
int M = INF,po = l;
for(int i = l;i <= R[p];++i) if(M > a[i]) M = a[i],po = i;
for(int i = L[q];i <= r;++i) if(M > a[i]) M = a[i],po = i;
int _ = INF,op = l;
for(int i = p+1;i <= q-1;++i) if(_ > Min[i]) _ = Min[i],op = i;
if(_ < M){
for(int i = L[op];i <= R[op];++i){
if(M > a[i]) M = a[i],po = i;
}
}
return po;
}
ll solve(int l,int r){
if(l > r) return 0;
else if(l == r) return b[l] = a[l];
int pos = Find(l,r);//找到区加最小值点的位置
ll sum1 = solve(pos+1,r);//分而治之
ll sum2 = solve(l,pos-1);
if(sum1 + (pos-l+1)*a[pos] > sum2 + (r - pos + 1)*a[pos]){
for(int i = l;i <= pos;++i) b[i] = a[pos];
return sum1 + (pos-l+1)*a[pos] ;
}
else {
for(int i = pos;i <= r;++i) b[i] = a[pos];
return sum2 + (r - pos + 1)*a[pos];
}
}
int main(){
int n = read();
for(int i = 1;i <= n;++i) a[i] = read();
int t = sqrt(n);//分块
for(int i = 1;i <= t;++i) L[i] = (i-1)*t + 1,R[i] = i*t;
if(R[t] < n) t++,L[t] = R[t-1] + 1,R[t] = n;
for(int i = 1;i <= t;++i){
Min[i] = INF;
for(int j = L[i];j <= R[i];++j){
pos[j] = i;Min[i] = min(Min[i],a[j]);
}
}
solve(1,n);//分治求和的最大值
for(int i = 1;i <= n;++i){
cout << b[i] <<' ';
}
}