ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【学习笔记】可持久化权值线段树--主席树 (静态)

2022-09-16 12:02:03  阅读:217  来源: 互联网

标签:rs -- 线段 mid int tag que include 化权值


001 前置芝士

(1)动态开点线段树

(2)动态开点维护权值线段树

(3)可持久化数组(可持久化线段树)

(4)掌握权值线段树以及查询全局第k大/小值

002 动态开点

我们知道,开一棵线段树数组所需空间为4*MAXN,当MAXN过大时,显然会MLE,那有没有什么优化空间的方法呢?

当然有(废话,要是没有我还写什么

动态开点

顾名思义,就是动态地新开节点。平时使用线段树时,建树过程中直接分成两部分向下递归建树,明显的,这么做会有冗余产生(因为递归时建了某一子节点但可能根本没有用到该节点)。对于这类冗余,我们完全没有必要开这一节点。解决办法很简单,现用现开,没有用的我就不开,用到时在新建节点,可以很大程度上的优化空间复杂度,代码很简单啦qwq

OPEN NODE

void open_node(int &p,int l,int r) //p一定要传址调用
{
    p=++cnt;
    t[p].val=sum[r]-sum[l-1]; //sum类似于前缀和,这里是区间加操作
}

query and update 操作就是在开头加上开点的操作,没什么好说的

动态开点线段树(区间加 区间查询

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<algorithm>
#define int long long

using namespace std;

const int maxn=1e6+5;

inline int read()
{
	int w=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-')
		{
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		w=(w<<3)+(w<<1)+(ch^48);
		ch=getchar();
	}
	return w*f;
}

struct s_t
{
	int ls;
	int rs;
	int val;
	int tag;
}t[maxn*4];

int root;

int sum[maxn];

int n,q,cnt;

int a[maxn];

void open_node(int &p,int l,int r)
{
	p=++cnt;
	t[p].val=sum[r]-sum[l-1];
}

void push_up(int p,int l,int r)
{
	if(l==r)
	{
		return ;
	}
	
	int mid=(l+r)>>1;
	
	if(t[p].ls==0)
	{
		open_node(t[p].ls,l,mid);
	}
	
	if(t[p].rs==0)
	{
		open_node(t[p].rs,mid+1,r);
	}
	
	t[p].val=t[t[p].ls].val+t[t[p].rs].val;
}

void push_down(int p,int l,int r)
{
	if(t[p].tag)
	{
		if(l==r)
		{
			return ;
		}
		
		int mid=(l+r)>>1;
	
		if(t[p].ls==0)
		{
			open_node(t[p].ls,l,mid);
		}
	
		if(t[p].rs==0)
		{
			open_node(t[p].rs,mid+1,r);
		}
	
		t[t[p].rs].tag+=t[p].tag;
		t[t[p].ls].tag+=t[p].tag;
		t[t[p].ls].val+=(mid-l+1)*t[p].tag;
		t[t[p].rs].val+=(r-mid)*t[p].tag;
		
		t[p].tag=0;
	}
	
}

void update(int &p,int l,int r,int l_que,int r_que,int k)
{
	if(p==0)
	{
		open_node(p,l,r);
	}
	
	if(l_que<=l && r<=r_que)
	{
		t[p].val+=(r-l+1)*k;
		t[p].tag+=k;
		return ;
	}
	
	push_down(p,l,r);
	
	int mid=(l+r)>>1;
	
	if(l_que<=mid)
	{
		update(t[p].ls,l,mid,l_que,r_que,k);
	}
	
	if(r_que>mid)
	{
		update(t[p].rs,mid+1,r,l_que,r_que,k);
	}
	
	push_up(p,l,r);
}

int query(int &p,int l,int r,int l_que,int r_que)
{
	if(p==0)
	{
		open_node(p,l,r);
	}
	
	if(l_que<=l && r<=r_que)
	{
		return t[p].val;
	}
	
	push_down(p,l,r);
	
	int mid=(l+r)>>1;
	
	int ans=0;
	
	if(l_que<=mid)
	{
		ans+=query(t[p].ls,l,mid,l_que,r_que);
	}
	
	if(r_que>mid)
	{
		ans+=query(t[p].rs,mid+1,r,l_que,r_que);
	}
	
	return ans;
}

signed main()
{
	n=read();
	q=read();
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
		sum[i]=sum[i-1]+a[i];
	}
	
	for(int i=1;i<=q;i++)
	{
		int opt=read();
		
		if(opt==1)
		{
			int l=read();
			int r=read();
			int k=read();
			update(root,1,n,l,r,k);
		}
		
		if(opt==2)
		{
			int l=read();
			int r=read();
			cout<<query(root,1,n,l,r)<<endl;
		}
	}
	
	return 0;
}

标签:rs,--,线段,mid,int,tag,que,include,化权值
来源: https://www.cnblogs.com/SitoASK/p/16699337.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有