[blocking] blocking Beginner Level 1 ~ 4

Posted by fewtrem on Sat, 22 Jan 2022 21:59:39 +0100

What is blocking

After learning the segment tree and tree array, these two data structures can solve most of the problems, but it is not difficult to find their shortcomings in the process of use

  • Tree array O ( ( N + M ) l o g N ) O((N+M)logN) O((N+M)logN): too limited to be extended to general topics
  • Segment tree O ( ( N + M ) l o g N ) O((N+M)logN) O((N+M)logN): although it can be extended to many topics, it also has many types, but it is not intuitive, long code and many details

Blocking came into being

The basic idea of blocking is to preprocess and save some information through appropriate division, and exchange space for time to achieve "space-time balance" -- algorithm competition

To put it more popularly, it is a violence algorithm optimized according to some method. Compared with line segment tree and tree array, the idea of blocking is simpler and more general, and the code is easy to implement.

Basic process of blocking

Block, block, as the name suggests, is to divide a sequence into several segments for operation.

Usually, A sequence A is divided into several, no more than ⌊ N ⌋ \lfloor \sqrt{N} \rfloor ⌊N ⌋, where the left end point of paragraph i is ( i − 1 ) ⌊ N ⌋ + 1 (i-1)\lfloor \sqrt{N} \rfloor +1 (i−1)⌊N ⌋ + 1, right endpoint is m i n ( i ∗ ⌊ N ⌋ , N ) min(i*\lfloor \sqrt{N} \rfloor,N) min(i∗⌊N ​⌋,N)

As shown in the figure below:

The rest is to operate on different paragraphs according to the requirements of the topic

Time complexity

Because the number and length of segments are O ( N ) O(\sqrt N) O(N ) so the time complexity of the whole algorithm is about O ( ( N + M ) ∗ N ) O((N+M)*\sqrt N) O((N+M)∗N ​).

Examples

Introduction to blocking 1

The sequence is divided into blocks according to the above method. Each time the addition operation is performed, add is used to represent the "incremental mark" of a certain section, that is, the value added to the whole section.

For an interval addition operation (l,r,c):

  • If l and R are in the same interval, then directly order a [ l ] a[l] a[l]~ a [ r ] a[r] a[r] all plus c
  • If they are not in the same interval: add c to the whole block i,add[i] between l~r, then the part whose beginning and end are not the whole block is added directly as in the first step.

Finally, when asking for the value of a number, pay attention to add the value in the add array.

Of course, you can also write an interval addition, interval summation and two questions

Introduction to blocking 2

As usual, the sequence is divided into blocks, and each block is sorted by preprocessing. The query is binary search

Introduction to blocking 3

The same as the second question, change the dichotomy to query the maximum value less than a certain number.

Introduction to blocking 4

There it is, wild interval plus!

Preprocess the array sum, record the interval of a certain section I and sum[i], as well as the incremental array add. The operation of the add array is shown in question 1. The specific operation of the sum array is explained in detail below:

  • For a whole paragraph i, s u m [ i ] + = ( r [ i ] − l [ i ] + 1 ) ∗ c sum[i]+=(r[i]-l[i]+1)*c sum[i]+=(r[i]−l[i]+1)∗c
  • If it is not a whole paragraph, then s u m [ i ] + = ( l [ i + 1 ] − L ) ∗ c sum[i]+=(l[i+1]-L)*c sum[i]+=(l[i+1] − L) * c or s u m [ i ] + = ( R − r [ i − 1 ] ) ∗ c sum[i]+=(R-r[i-1])*c sum[i]+=(R−r[i−1])∗c

The final answer is

  • If in a whole paragraph a n s = s u m [ i ] + a d d [ i ] ∗ ( r [ i ] − l [ i ] ) ans=sum[i]+add[i]*(r[i]-l[i]) ans=sum[i]+add[i]∗(r[i]−l[i])
  • Otherwise, use violence to directly calculate the two parts of the whole paragraph (at most) N \sqrt N N ​).

code

//Introduction to blocking 4
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=50086;
int n,a[N],l[N],r[N],pos[N];
LL sum[N],add[N];
void change(int ll,int rr,LL d)
{
	int p=pos[ll],q=pos[rr];
	if(p==q)
	{
		for(int i=ll;i<=rr;i++)
		{
			a[i]+=d;
		}
		sum[p]+=d*(rr-ll+1);
	}
	else {
		for(int i=p+1;i<=q-1;i++) add[i]+=d;
		for(int i=ll;i<=r[p];i++) a[i]+=d;
		sum[p]+=d*(r[p]-ll+1);
		for(int i=l[q];i<=rr;i++) a[i]+=d;
		sum[q]+=d*(rr-l[q]+1);
	}
}
LL ask(int ll,int rr)
{
	int p=pos[ll],q=pos[rr];
	LL ans=0;
	if(p==q)
	{
		for(int i=ll;i<=rr;i++) ans+=a[i];
		ans+=add[p]*(rr-ll+1);
	}
	else {
		for(int i=p+1;i<=q-1;i++)
		{
			ans+=sum[i]+add[i]*(r[i]-l[i]+1);
		}
		for(int i=ll;i<=r[p];i++) ans+=a[i];
		ans+=add[p]*(r[p]-ll+1);
		for(int i=l[q];i<=rr;i++) ans+=a[i];
		ans+=add[q]*(rr-l[q]+1);
	}
	return ans;
}
int main()
{
 	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>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];
		}
	} 
	int m=n;
	while(m--)
	{
		int pd,ll,rr,c;
		cin>>pd>>ll>>rr>>c;
		if(pd==1)
		{
			cout<<ask(ll,rr)%(c+1)<<endl;
		}
		else 
		{
			change(ll,rr,c);
		}
	}
	return 0;
}


Topics: data structure