【学习笔记】可持久化权值线段树--主席树 (静态)
作者:互联网
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