Line segment tree template + example questions

Line segment tree is a binary search number, generally used to implement dynamic interval queries. It is similar to tree arrays, but operations that can be implemented with tree arrays can also be implemented with line segment trees.

Generally, line segment trees are used for the following operations:

Tree building, single point modification, interval query, interval modification.

The first thing to do is to build a tree:

void bui(int id,int l,int r)
{
	if(l==r)
	{
		tr[id]=a[l];
		return ;
	}
	int mid=(l+r)/2;
	bui(id*2,l,mid);
	bui(id*2+1,mid+1,r);
	tr[id]=max(tr[id*2],tr[id*2+1]);//tr[id]=tr[id*2]+tr[id*2+1];
}//查询最大值与区间和,最小值同理

Single point modification:

void gexi(int id,int l,int r,int x,int v)
{
	if(l==r)
	{
		tr[id]=v;
		return ;
	}
	int mid=(l+r)/2;
	if(x<=mid)
	gexi(id*2,l,mid,x,v);
	else 
	gexi(id*2+1,mid+1,r,x,v);
	tr[id]=max(tr[id*2],tr[id*2+1]);//tr[id]=tr[id*2]+tr[id*2+1]
}//查询最大值与区间和

Interval query:

int find(int id,int l,int r,int x,int y)
{
	if(x<=l&&r<=y)
	{
		return tr[id];
	}
	int mid=(l+r)/2,ans=0;
	if(x<=mid)
	ans=max(ans,find(id*2,l,mid,x,y));//ans+=find(id*2,l,mid,x,y);
	if(y>mid)
	ans=max(ans,find(id*2+1,mid+1,r,x,y));//ans+=find(id*2+1,mid+1,r,x,y);
	return ans;
}

Interval modification:

void push_up(int id)
{
	tr[id]=tr[id*2]+tr[id*2+1];
}
void push_down(int id,int l,int r)
{
	if(lazy[id])//如果有lazy标记 
	{
		int mid=(l+r)/2;
		lazy[id*2]+=lazy[id];//左孩子的lazy加上它的lazy 
		lazy[id*2+1]+=lazy[id];//右孩子的lazy加上它的lazy 
		tr[id*2]+=lazy[id]*(mid-l+1);
		tr[id*2+1]+=lazy[id]*(r-mid);
		lazy[id]=0;//清除lazy标记 
	}
}
void qjgx(int id,int l,int r,int x,int y,int v)
{
	if(x<=l&&r<=y)//[l,r]被[x,y]包含了 
	}
	{
		lazy[id]+=v;//暂时不下传修改的值,加进lazy标记 
		tr[id]+=v*(r-l+1); 
		return ;
	}
	push_down(id,l,r);//要更新节点了,开始下传修改的值 
	int mid=(l+r)/2;
	if(x<=mid)
	qjgx(id*2,l,mid,x,y,v);//只有x<=mid(即[l,mid]有一部分是被[x,y]覆盖了的)才需要去更新[l,mid]
	if(y>mid)
	qjgx(id*2+1,mid+1,r,x,y,v);
	push_up(id); //子节点更新后父节点也更新 
}

Below are two example questions. You can try these operations.

1: Enemy troop formation

The enemy has N engineer camps, numbered 1∼N.

Initially, there are ai people in the i-th camp.

There are several commands next, and the commands have 4 forms:

Add ij, i and j are positive integers, indicating that j people are added to the i-th camp. (j does not exceed 30)
Sub ij, i and j are positive integers, indicating that the i-th camp reduces j people. (j does not exceed 30)
Query ij, i and j are positive integers (i≤j), which means querying the total number of people in the i-th to j-th campsites.
End means end. This command will only appear as the last command.
Please calculate the answer for each Query.

Input format
The first line contains the integer T, indicating that there are T sets of test data.

The first row of each set of data contains an integer N.

The second line contains N integers a1, a2,…,aN.

The next few lines, each line contains a command, the format is as described in the title.

Output format
For the i-th group of data, first output a line of Case i:, and then for each Query query, output an integer in one line, indicating the total number of people in the segment being queried.

The data range is
1≤T≤10,
1≤N≤50000,
1≤ai≤50.
Each set of data has a maximum of 40000 commands,
which ensures that the number of people in any camp will not be reduced to a negative number.

Input example:

1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End

Output sample:

Case 1:
6
33
59

AC code:

#include <bits/stdc++.h>
using namespace std;
#define p 50010
int tr[4*p],a[4*p];
void bui(int id,int l,int r)
{
	if(l==r)
	{
		tr[id]=a[l];
		return ;
	}
	int mid=(l+r)/2;
	bui(id*2,l,mid);
	bui(id*2+1,mid+1,r);
	tr[id]=tr[id*2]+tr[id*2+1];
}
int find(int id,int l,int r,int x,int y)
{
	if(x<=l&&r<=y)
	{
		return tr[id];
	}
	int mid=(l+r)/2,ans=0;
	if(x<=mid)
	ans+=find(id*2,l,mid,x,y);
	if(y>mid)
	ans+=find(id*2+1,mid+1,r,x,y);
	return ans;
}
void gexi(int id,int l,int r,int x,int v)
{
	if(l==r)
	{
		tr[id]+=v;
		return ;
	}
	int mid=(l+r)/2;
	if(x<=mid)
	gexi(id*2,l,mid,x,v);
	else 
	gexi(id*2+1,mid+1,r,x,v);
	tr[id]=tr[id*2]+tr[id*2+1];
}
int main()
{
	int t;
	scanf("%d",&t);
	for(int k=1;k<=t;k++)
	{
		int n;
		scanf("%d",&n);
		memset(a,0,sizeof(a));
		memset(tr,0,sizeof(tr));
		for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
		bui(1,1,n);
		char x[10];
		int aa,bb,cc;
		cout<<"Case "<<k<<":"<<endl;
		while(~scanf("%s",x))
		{
			if(x[0]=='Q')
			{
				scanf("%d%d",&aa,&bb);
				printf("%d\n",find(1,1,n,aa,bb));
			}
			else if(x[0]=='A')
			{
				scanf("%d%d",&aa,&bb);
				gexi(1,1,n,aa,bb);
			}
			else if(x[0]=='S')
			{
				scanf("%d%d",&aa,&bb);
				gexi(1,1,n,aa,-bb);
			}
			else
			break;
		}
	}
	return 0;
}

2: A simple integer problem 2

Given an array A of length N, and M instructions, each instruction may be one of the following two:

C lrd means adding d to A[l], A[l+1],...,A[r].
Q lr, represents the sum of the l∼rth numbers in the query sequence.
For each query, output an integer representing the answer.

Input format: The
first line contains two integers N and M.

The second line contains N integers A[i].

The next M lines represent M instructions, and the format of each instruction is as shown in the title description.

Output format
For each query, output an integer representing the answer.

Each answer should be on one line.

Data range
1≤N,M≤105,
|d|≤10000,
|A[i]|≤109

Input example:

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Output sample:

4
55
9
15

AC code:

#include <bits/stdc++.h>
#define int long long
using namespace std;
int sumv[10000001],n,m,a[10000001],lazy[10000001];
void push_up(int id)
{
      sumv[id] = sumv[id * 2] + sumv[id * 2 + 1];
}
void push_down(int id,int l,int r)
{
	  if(lazy[id])
	  {
	    int mid = (l + r) / 2;
	    lazy[id * 2] += lazy[id];
	    lazy[id * 2 + 1] += lazy[id];
	    sumv[id * 2] += lazy[id] * (mid - l + 1);
	    sumv[id * 2 + 1] += lazy[id] * (r - mid);
	    lazy[id] = 0;
	  }
}
void bui(int id,int l,int r)
{
	  if(l == r)
	  {
	    sumv[id] = a[l];
	    return ;
	  }
	  int mid = (l + r) / 2;
	  bui(id * 2,l,mid);
	  bui(id * 2 + 1,mid + 1,r);
	  sumv[id] = sumv[id * 2] + sumv[id * 2 + 1];
}
void qjgx(int id,int l,int r,int x,int y,int v)
{
	  if(l >= x && r <= y)
	  {
	    lazy[id] += v;
	    sumv[id] += v * (r - l + 1);
	    return ;
	  }
	  push_down(id,l,r);
	  int mid = (l + r) / 2;
	  if(x <= mid) qjgx(id * 2,l,mid,x,y,v);
	  if(y > mid) qjgx(id * 2 + 1,mid + 1,r,x,y,v);
	  push_up(id);
}
int find(int id,int l,int r,int x,int y)
{
	  if(x <= l && r <= y) return sumv[id];
	  push_down(id,l,r);
	  int mid = (l + r) / 2,ans = 0;
	  if(x <= mid) ans += find(id * 2,l,mid,x,y);
	  if(y > mid) ans += find(id * 2 + 1,mid + 1,r,x,y);
	  return ans;
}
signed main()
{
	  cin>>n>>m;
	  for(int i = 1; i <= n; i++) cin>>a[i];
	  bui(1,1,n);
	  while(m--)
	  {
	  	string p;
	    int k,x,y;
	    cin>>p>>x>>y;
	    if(p == "C")
	    {
	      cin>>k;
	      qjgx(1,1,n,x,y,k);
	    }
	    else cout<<find(1,1,n,x,y)<<'\n';
	  }
  return 0;
}

Next articlecodeforces round 885 (div. 2)

Guess you like

Origin blog.csdn.net/weixin_74088105/article/details/131856476