线段树模板(结构体)

线段树研究了两天了,总算有了点眉目,今天也把落下的题,补了一下。 贴一份线段树模板

线段树的特点:

1. 每一层都是区间[a, b]的一个划分,记 L = b - a

2. 一共有log2L层

3. 给定一个点p,从根到叶子p上的所有区间都包含点p,且其他区间都不包含点p。

4. 给定一个区间[l; r],可以把它分解为不超过2log2 L条不相交线段的并。

总结来说:线段树最近本的应用是4点:

1.单点更新:单点替换、单点增减

2.单点询问

3.区间询问:区间之和、区间最值

4.区间更新:区间替换、区间增减

下面是 这4个基本操作的模板:(有点儿挫)

单点替换  区间求最大

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 200004
#define MAX INT_MAX
#define MIN INT_MIN
struct node
{
	int left,right;
	int num; //
}T[4*N];
int ans=0;
void Creat(int left,int right,int id)//建树
{
	T[id].left =left;
	T[id].right =right;
	T[id].num =0;
	if(T[id].left ==T[id].right )
		return ;
	Creat(left,(left+right)/2,2*id);
	Creat((left+right)/2+1,right,2*id+1);
}
void UPdata(int id,int i,int j)

{
	if(T[id].left<=i&&T[id].right >=i)
		T[id].num = j;
	if(T[id].left ==T[id].right )
		return;
	if(i>T[id].right )
		return;
	if(i<T[id].left )
		return;
	int mid=(T[id].left +T[id].right )/2;
	if(i<=mid)
		UPdata(id*2,i,j);
	else
		UPdata(id*2+1,i,j);
	T[id].num = max(T[id*2].num,T[id*2+1].num);
}
void query(int id,int l,int r)//区间&&单点查询,l-r 区间内的所有人
{
	int mid=(T[id].left +T[id].right)/2;
	if(T[id].left ==l&&T[id].right ==r)
	{
		if(T[id].num >ans)
            ans = T[id].num;
		return;
	}
	if(r<=mid)
		query(2*id,l,r);
	else if(l>mid)
		query(2*id+1,l,r);
	else
	{
		query(2*id,l,mid);
		query(2*id+1,mid+1,r);
	}

}

int main()
{
    int n,m,x,l,r;
    char str[5];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        Creat(1,n,1);
        for(int i = 1;i<=n;i++)
        {
            scanf("%d",&x);
            UPdata(1,i,x);
        }
        for(int i = 1;i<=m;i++)
        {
            scanf("%s",str);
            if(str[0]=='Q')
            {
                scanf("%d%d",&l,&r);
                ans = -9999999;
               query(1,l,r);
                printf("%d\n",ans);
                ans = -9999999;
            }
            else if(str[0]=='U')
            {
                scanf("%d%d",&l,&r);
                UPdata(1,l,r);
            }
        }
    }
    return 0;
}

单点增减  区间求和

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 50004
#define MAX INT_MAX
#define MIN INT_MIN
struct node
{
	int left,right;
	int num; //
}T[4*N];
int ans=0;
void Creat(int left,int right,int id)//建树
{
	T[id].left =left;
	T[id].right =right;
	T[id].num =0;
	if(T[id].left ==T[id].right )
		return ;
	Creat(left,(left+right)/2,2*id);
	Creat((left+right)/2+1,right,2*id+1);
}
void UPdata(int id,int i,int j)//单点更新
{
	if(T[id].left<=i&&T[id].right >=i)
		T[id].num +=j;
	if(T[id].left ==T[id].right )
		return;
	if(i>T[id].right )
		return;
	if(i<T[id].left )
		return;
	int mid=(T[id].left +T[id].right )/2;
	if(i<=mid)
		UPdata(id*2,i,j);
	else
		UPdata(id*2+1,i,j);
}
void query(int id,int l,int r)//区间&&单点查询
{
	int mid=(T[id].left +T[id].right)/2;
	if(T[id].left ==l&&T[id].right ==r)
	{
		ans+=T[id].num ;
		return;
	}
	if(r<=mid)
		query(2*id,l,r);
	else if(l>mid)
		query(2*id+1,l,r);
	else
	{
		query(2*id,l,mid);
		query(2*id+1,mid+1,r);
	}

}
int main()
{
	int t,n,num,l,r,C=1;
	char str[20];
	scanf("%d",&t);
	while(t--)
	{
		printf("Case %d:\n",C++);
		scanf("%d",&n);
		Creat(1,n,1);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&num);
			UPdata(1,i,num);
		}

		while(scanf("%s",str))
		{
			if(str[0]=='E')
				break;
		else if(str[0]=='Q')
			{
				scanf("%d%d",&l,&r);
				query(1,l,r);
				printf("%d\n",ans);
				ans=0;
			}
		else if(str[0]=='A')
			{
				scanf("%d%d",&l,&r);
				UPdata(1,l,r);
			}
		else if(str[0]=='S')
			{
				scanf("%d%d",&l,&r);
				UPdata(1,l,-r);
			}
       /* else if(str[0]=='D')//单点查询
            {
                scanf("%d",&l);
                query(1,l,l);
                printf("%d\n",ans);
                ans = 0;
            }*/

		}

	}
	return 0;
}

区间增减

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL __int64
const int maxn = 500100;
using namespace std;
#define MAX INT_MAX
#define MIN INT_MIN
struct node
{
    int l,r;
    LL add,sum;  //add作为一个数的累加和,同时起标记的作用,即lazy数组的作用
}T[300010];
int a[100005];   //add必须是__int64;
void putup(int id)
{
    T[id].sum=T[2*id].sum+T[2*id+1].sum;
}
void putdown(int id)
{
    if(T[id].add) //更新左右孩子
    {
        T[2*id].add+=T[id].add;
        T[2*id].sum += (T[2*id].r-T[2*id].l+1)*T[id].add;
        T[2*id+1].add+=T[id].add;
        T[2*id+1].sum += (T[2*id+1].r-T[2*id+1].l+1)*T[id].add;
        T[id].add=0;  //取消标记
    }
}
void creat(int l,int r,int id)
{
    T[id].l=l;
    T[id].r=r;
    T[id].add=0;
    if(l==r)
    {
        T[id].sum=a[r];
        return;
    }
    int mid=(l+r)>>1;
    creat(l,mid,2*id);
    creat(mid+1,r,2*id+1);
    putup(id);
}
void update(int from,int to,LL add,int id)
{
    if(from<=T[id].l&&to>=T[id].r)
    {
        T[id].add +=add;
        T[id].sum += (T[id].r-T[id].l+1)*add;
        return;
    }

    putdown(id);
    if(from<=T[2*id].r)
        update(from,to,add,2*id);
    if(to>=T[2*id+1].l)
        update(from,to,add,2*id+1);
    putup(id);
}
LL query(int from,int to,int id)
{
    if(from==T[id].l&&to==T[id].r)
        return T[id].sum;

    putdown(id);
    if(from>=T[2*id+1].l)
        return query(from,to,2*id+1);
    else if(to<=T[2*id].r)
        return query(from,to,2*id);
    else
    return query(from,T[2*id].r,2*id) + query(T[2*id+1].l,to,2*id+1);
}
int main()
{
    int n,m,A,B;
    LL add;
    char str[5];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        creat(1,n,1);
        while(m--)
        {
            LL ans = 0;
            scanf("%s",str);
            if(str[0]=='C')
            {
                scanf("%d%d%I64d",&A,&B,&add);
                update(A,B,add,1);
            }
            else
            {
                scanf("%d%d",&A,&B);
                ans=query(A,B,1);
                printf("%I64d\n",ans);
            }
        }
    }
}

区间替换

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL __int64
const int maxn = 500100;
using namespace std;
#define MAX INT_MAX
#define MIN INT_MIN
struct node
{
    int l,r;
    LL add,sum;
}T[400010];
int a[100005];
void putup(int id)
{
    T[id].sum=T[2*id].sum+T[2*id+1].sum;
}
void putdown(int id)
{
    if(T[id].add)
    {
        T[2*id].add= T[2*id+1].add= T[id].add;
        T[2*id].sum = (T[2*id].r-T[2*id].l+1)*T[id].add;
        T[2*id+1].sum = (T[2*id+1].r-T[2*id+1].l+1)*T[id].add;
        T[id].add=0;
    }
}
void creat(int l,int r,int id)
{
    T[id].l=l;
    T[id].r=r;
    T[id].add=0;
  //  T[id].sum = 1;
    if(l==r)
    {
        T[id].sum=a[r];
        return;
    }
    int mid=(l+r)>>1;
    creat(l,mid,2*id);
    creat(mid+1,r,2*id+1);
    putup(id);
}
void update(int from,int to,LL add,int id)
{
    if(from<=T[id].l&&to>=T[id].r)
    {
        T[id].add = add;
        T[id].sum = (T[id].r-T[id].l+1)*add;
        return;
    }

    putdown(id);
    if(from<=T[2*id].r)
        update(from,to,add,2*id);
    if(to>=T[2*id+1].l)
        update(from,to,add,2*id+1);
    putup(id);
}
LL query(int from,int to,int id)
{
    if(from==T[id].l&&to==T[id].r)
        return T[id].sum;

    putdown(id);
    if(from>=T[2*id+1].l)
        return query(from,to,2*id+1);
    else if(to<=T[2*id].r)
        return query(from,to,2*id);
    else
    return query(from,T[2*id].r,2*id) + query(T[2*id+1].l,to,2*id+1);
}
int main()
{
    int n,m,A,B;
    LL add;
    char str[5];
    while(~scanf("%d%d",&n,&m))
      {
       // C++;
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        creat(1,n,1);
        while(m--)
        {
            scanf("%s",str);
            if(str[0]=='T')
            {
                 scanf("%d%d%I64d",&A,&B,&add);
            update(A,B,add,1);
            }
           else if(str[0]=='Q')
           {
               scanf("%d%d",&A,&B);
               cout<<query(A,B,1)<<endl;
           }
        }

    }

}

线段树模板(结构体),布布扣,bubuko.com

时间: 2024-08-10 17:01:34

线段树模板(结构体)的相关文章

Hihocoder #1077 : RMQ问题再临-线段树(线段树:结构体建树+更新叶子往上+查询+巧妙使用father[]+线段树数组要开大4倍 *【模板】)

#1077 : RMQ问题再临-线段树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上回说到:小Hi给小Ho出了这样一道问题:假设整个货架上从左到右摆放了N种商品,并且依次标号为1到N,每次小Hi都给出一段区间[L, R],小Ho要做的是选出标号在这个区间内的所有商品重量最轻的一种,并且告诉小Hi这个商品的重量.但是在这个过程中,可能会因为其他人的各种行为,对 某些位置上的商品的重量产生改变(如更换了其他种类的商品). 小Ho提出了两种非常简单的方法,但是都不能

线段树模板及总结

在信息学竞赛中,经常遇到这样一类问题:这类问题通常可以建模成数轴上的问题或是数列的问题,具体的操作一般是每次对数轴上的一个区间或是数列中的连续若干个数进行一种相同的处理.常规的做法一般依托于线性表这种数据结构,导致了处理只能针对各个元素逐个进行,因此算法的效率较低. 线段树是一种能够有效处理区间操作的高级数据结构,利用这种数据结构,我们能够设计出针对上述问题更加高效的算法. 线段树的题目通常比较明显,一般一个很明显的特征是m次对某一区间长度的查询.或者是修改.所以我们通常需要的只是将线段树的模型

[ACM] 线段树模板

#include<iostream> #include<cmath> using namespace std; #define maxn 200005 class Node{ public: int l,r; int add;//附加值 int sum; }node[maxn]; int getRight(int n){//获得满足2^x>=n的最小x[从0层开始,给编号获得层数] return ceil(log10(n*1.0)/log10(2.0)); } void bu

[POJ2104] 区间第k大数 [区间第k大数,可持久化线段树模板题]

可持久化线段树模板题. #include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <vector> using namespace std; int n,q,tot,a[110000]; in

hdu 4819 二维线段树模板

/* HDU 4819 Mosaic 题意:查询某个矩形内的最大最小值, 修改矩形内某点的值为该矩形(Mi+MA)/2; 二维线段树模板: 区间最值,单点更新. */ #include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 1010; int N, Q; struct Nodey { int l, r; int Max, Min; }; int locx[MAXN], l

【HDU 4819】Mosaic 二维线段树模板

二维线段树的模板题,和一维一样的思路,更新的时候注意一下细节. 存模板: /* 二维线段树模板整理 */ #include<cstdio> #include<algorithm> using namespace std; #define lson (pos<<1) #define rson (pos<<1|1) const int maxn = 805; const int INF = (1 << 30); int n; int posX[max

LA 2191电位计(线段树模板题)

线段树模板题,没啥好说的.....注意输出是case之间空一行就行.........之前一直没注意,一直wa 代码如下: #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #includ

洛谷P3372线段树模板1——线段树

题目:https://www.luogu.org/problemnew/show/P3372 线段树模板. 代码如下: #include<iostream> #include<cstdio> using namespace std; long long n,m,a[100005],ct; struct N{ long long lazy,sum; long long ls,rs; }p[200005]; void pushdown(long long cur,long long l

P3373 线段树模板

好,这是一个线段树模板. 1 #include <cstdio> 2 using namespace std; 3 const long long int N=1000010; 4 long long int sum[N],tag1[N],tag2[N],mo; 5 6 void build(int l,int r,int o) 7 { 8 tag1[o]=1; 9 if(l==r) 10 { 11 scanf ("%d",&sum[o]); 12 return;