入门线段树模板总结

最近练了洛谷的三道入门线段树题目
算是熟练了下模板,理解了其思维内涵了

首先是看的教程:
https://www.cnblogs.com/AC-King/p/7789013.html 这个很全面,涵盖了主席树了
https://www.luogu.org/blog/khong-biet/Introduction-of-zkwSegmentTree 很好的非递归线段树,用zkw数就看这个
https://www.luogu.org/blog/pks-LOVING/senior-data-structure-qian-tan-xian-duan-shu-segment-tree 讲的比较本质,但不是很通俗易懂的递归线段树

个人理解:
线段树在不进行区间修改前的部分还是很好理解的,需要注意递归式线段树,先往下处理过程,基本每个函数最后需要通过子树的值维护当前节点的值,个人比较喜欢用struct包装树的节点,保存每个节点维护区间的左右端点的信息。

题目和模板:https://www.luogu.org/problem/P1972

正常递归写法

,由于数据被加强,有两组数据会TLE
这道题也挺有意思的:需要离线做:
在这里插入图片描述
思路大致如上,比如4 5 6 3 4 5这段数
其对应线段树叶子的值就是0 0 1 1 1 1,同一类数字,只有最右边的那个值为1,其余为0,这样区间和就可以维护区间种类数了。离线排序做,就O(nlogn)复杂度而已。

#include<bits/stdc++.h>
#define LL long long
#define ms0(x) memset(x,0,sizeof(x))
#define ms-1(x) memset(x,-1,sizeof(x))
using namespace std;
const int maxn = 1e6;
const int iinf=0x3f3f3f3f;
int a[maxn]={
   0};//线段树维护的数组 
struct node
{
   
	int l,r;	//包装了每个节点所维护的对应区间
	LL sum; 	//线段树要维护的值(最大值,和等) 
}tr[maxn<<2];node nx,ny;
node build(int  i,int l,int   r)//这里的i只的是对应存储线段树的数组 
{
   
	tr[i].l=l;
	tr[i].r=r;
	if(l==r)
	{
   
		tr[i].sum=a[l];
		return tr[i];
	}
	int mid=(l+r)/2;
	nx=build(i<<1,l,mid);
	ny=build(i<<1|1,mid+1,r);
	tr[i].sum=nx.sum+ny.sum;
	return tr[i];
}
int update(int  i,int & pos,const int & val)//单点更新
{
   
	if(pos<tr[i].l||tr[i].r<pos)
		return tr[i].sum;
	if(tr[i].l==pos&&tr[i].r==pos)
		return tr[i].sum+=val;
	return tr[i].sum=update(i<<1,pos,val)+update(i<<1^1,pos,val);	
} 
int query(int  i,int  l,int r)//注意这里的l,r是询问的区间
{
   
	if(tr[i].l>r||tr[i].r<l)
		return 0;
	if(l<=tr[i].l&&tr[i].r<=r)
		return tr[i].sum;
	int x,y;
	return query(i<<1,l,r)+query(i<<1|1,l,r);
}
inline int re(){
   
    int 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<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
struct INTERVAL{
   
	int l,r;int id;
	INTERVAL(int &_l,int &_r,int &_id):l(_l),r(_r),id(_id)
	{
   
	}
	INTERVAL(){
   
	}
	bool operator<(const INTERVAL & tmp)const{
   
	if(r==tmp.r)
		return l<tmp.l;
	return r<tmp.r;
	}
}inter[maxn];
int num[maxn];int pos[maxn]={
   0};int ans[maxn];
int main()
{
   
	int n;
	n=re();
	for(register int j=1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值