树套树

  • 树套树是一种相当高级的数据结构,同时因为树本身的种类就有很多,因此“树套树”就千变万化,层出不穷。
    但是一般而言,树状数组、线段树以及平衡树是树套树中相对常用的树。同时,因为树套树本身常数过于巨大,因此一般而言解题时能用树状数组就别用线段树,能用线段树就别用平衡树。

P2617 Dynamic Rankings

  • 带单点修改的主席树,不强于树套树模板题(虽然本质不太一样)

  • 如果不带修的话就是区间查询第k小,就是主席树板子题,但是这里带修了。

  • 由于主席树本质上在维护值域线段树前缀和的信息,带修时就需要像暴力修改前缀和数组一样去 \(O(n)\) 地遍历整个前缀和数组后缀修改。
    但是我们普通前缀和是怎么修改的呢?就是用树状数组去动态地维护前缀和。

  • 把这个思路拓展一下到主席树上,我们就会发现,仍然是对于不同的 \(rt\),我们把每个 \(rt\) 当做树状数组上的一个点。
    修改时就同时修改 \(log\) 颗主席树的值,查询时就用类似于普通树状数组的方式统计前缀和。

  • 当然,主席树记得离散化。时间复杂度 \(O(nlog^2n)\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&(-x))
#define push_up(x) tr[u]=tr[ls[u]]+tr[rs[u]]
const int N=4e5+7;
const int M=4e7+7;
const int mlg=20;
int n,m,tr[M],ls[M],rs[M],rt[N],a[N],b[N],len,cnt=0,tcnt1=0,tcnt2=0,tmp1[20],tmp2[20],idcnt=0;
struct node
{
	char op;
	int l,r,x,k;
}qu[N];
int add(int u,int l,int r,int x,int w)
{
	if(!u) u=++idcnt;int mid=(l+r)>>1;
	if(l==r) {tr[u]+=w;return u;}
	if(x<=mid) ls[u]=add(ls[u],l,mid,x,w);
	else rs[u]=add(rs[u],mid+1,r,x,w);
	push_up(u);return u;
}
void pre_add(int loc,int x,int w)
{
	for(int i=loc;i<=n;i+=lowbit(i)) rt[i]=add(rt[i],1,len,x,w);
}
int query(int po1[20],int po2[20],int l,int r,int k)//记得返回的是b数组里面的值 
{
	if(l==r) return b[l];
	int sum1=0,sum2=0,po1l[20],po2l[20],po1r[20],po2r[20],num=0,mid=(l+r)>>1;
	for(int i=1;i<=tcnt1;i++)sum1+=tr[ls[po1[i]]];for(int i=1;i<=tcnt2;i++)sum2+=tr[ls[po2[i]]];
	num=sum2-sum1;
	if(num>=k){
		for(int i=1;i<=tcnt1;i++) po1l[i]=ls[po1[i]];for(int i=1;i<=tcnt2;i++) po2l[i]=ls[po2[i]];
		return query(po1l,po2l,l,mid,k);
	}
	else{
		for(int i=1;i<=tcnt1;i++) po1r[i]=rs[po1[i]];for(int i=1;i<=tcnt2;i++) po2r[i]=rs[po2[i]];
		return query(po1r,po2r,mid+1,r,k-num);
	}
}
int pre_query(int ql,int qr,int k)
{
	tcnt1=tcnt2=0;
	for(int i=ql-1;i>0;i-=lowbit(i)) tmp1[++tcnt1]=rt[i];for(int i=qr;i>0;i-=lowbit(i)) tmp2[++tcnt2]=rt[i];
	return query(tmp1,tmp2,1,len,k);
}
int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i],b[++cnt]=a[i];b[++cnt]=0;
	for(int i=1;i<=m;i++){cin>>qu[i].op;if(qu[i].op=='Q')cin>>qu[i].l>>qu[i].r>>qu[i].k;else cin>>qu[i].x>>qu[i].k,b[++cnt]=qu[i].k;}
	sort(b+1,b+cnt+1);len=unique(b+1,b+cnt+1)-b-1;
	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+len+1,a[i])-b,pre_add(i,a[i],1);
	for(int i=1;i<=m;i++) 
	{
		if(qu[i].op=='Q') cout<<pre_query(qu[i].l,qu[i].r,qu[i].k)<<'\n';
		else qu[i].k=lower_bound(b+1,b+len+1,qu[i].k)-b,pre_add(qu[i].x,qu[i].k,1),pre_add(qu[i].x,a[qu[i].x],-1),a[qu[i].x]=qu[i].k;
	}
	return 0;
}
posted @ 2024-12-12 09:34  all_for_god  阅读(62)  评论(0)    收藏  举报