可持久化线段树
Part1:线段树
思路:通过 \(O(logn)\) 的复杂度实现区间修改与查询
大概意思就是建一棵二叉树,节点代表一个区间,左儿子代表区间前一半,右儿子代表后一半,这样就可以将区间拆成log个区间拼在一起
#include<bits/stdc++.h>
using namespace std;
#define N 500010
int n,m;
long long a[N],b[N*2],d[N*2];
void build(int s,int t,int p)
{
if(s==t) d[p]=a[s];
else
{
int m=s+((t-s)>>1);
build(s,m,p*2),build(m+1,t,p*2+1);
d[p]=d[p*2]+d[p*2+1];
}
}
void update(int l,int r,int s,int t,int p,int v)
{
if(l<=s&&t<=r)
{
d[p]+=(t-s+1)*v;
b[p]+=v;
return;
}
int m=s+((t-s)>>1);
if(b[p]&&s!=t)
{
d[p*2]+=b[p]*(m-s+1),d[p*2+1]+=b[p]*(t-m);
b[p*2]+=b[p],b[p*2+1]+=b[p];
b[p]=0;
}
if(l<=m) update(l,r,s,m,p*2,v);
if(r>m) update(l,r,m+1,t,p*2+1,v);
d[p]=d[p*2]+d[p*2+1];
}
long long getsum(int l,int r,int s,int t,int p)
{
if(l<=s&&t<=r) return d[p];
int m=s+((t-s)>>1);
long long ans=0;
if(b[p])
{
d[p*2]+=b[p]*(m-s+1),d[p*2+1]+=b[p]*(t-m);
b[p*2]+=b[p],b[p * 2 + 1] += b[p];
b[p]=0;
}
if(l<=m) ans+=getsum(l,r,s,m,p*2);
if(r>m) ans+=getsum(l,r,m+1,t,p*2+1);
return ans;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
build(1,n,1);
for(int i=1;i<=m;i++)
{
int ty,l,r,w;
cin>>ty>>l>>r;
if(ty==1)
{
cin>>w;
update(l,r,1,n,1,w);
}
else
cout<<getsum(l,r,1,n,1)<<'\n';
}
return 0;
}
Part2:可持久化线段树
这道题我们可以开n棵线段树,第i棵代表 \(a_1-a_i\) 的分布,然后利用前缀和,将 \(r\) 的分布减去 \(l-1\) 的分布就是 \(l-r\) 的分布
但是这样的空间是 \(2n^2\),会炸掉,所以考虑用可持久化线段树优化空间
因为从 \(i-1\) 到 \(i\) 只会使一条链变化(因为只会更改一个叶子),所以只需要在原树基础上再开一条新链就可以了
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
#define mid ((l+r)>>1)
int n,m,a[N],b[N],q,l,r,k;
int root[N],tot;
int ls[N*25],rs[N*25],sum[N*25];
void build(int &u,int l,int r)
{
u=++tot;
if(l==r) return;
build(ls[u],l,mid);
build(rs[u],mid+1,r);
return;
}
void change(int &u,int pre,int l,int r,int p)
{
u=++tot;
sum[u]=sum[pre]+1,ls[u]=ls[pre],rs[u]=rs[pre];
if(l==r) return;
if(p<=mid) change(ls[u],ls[pre],l,mid,p);
else change(rs[u],rs[pre],mid+1,r,p);
}
int query(int s,int t,int l,int r,int k)
{
if(l==r) return l;
int x=sum[ls[t]]-sum[ls[s]];
if(k<=x) return query(ls[s],ls[t],l,mid,k);
else return query(rs[s],rs[t],mid+1,r,k-x);
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+n+1);
q=unique(b+1,b+n+1)-b-1;
build(root[0],1,q);
for(int i=1;i<=n;i++)
{
int x=lower_bound(b+1,b+q+1,a[i])-b;
change(root[i],root[i-1],1,q,x);
}
for(int i=1;i<=m;i++)
{
cin>>l>>r>>k;
cout<<b[query(root[l-1],root[r],1,q,k)]<<'\n';
}
return 0;
}

浙公网安备 33010602011771号