习题:二逼平衡树(树套树)

题目

传送门

思路

挺好的一道树套树的板子题

因为笔者过于菜鸡其实是懒

写了BIT套主席树

求区间第k大,前驱和后驱都是主席树的基本操作

所有此处要阐述的是修改操作

如果是直接单纯用主席树

那么修改一个节点就要修改n棵树

相当于单次修改的时间复杂度为\(O(n*log_n)\)

但是我们仔细思考一下整个过程,

我们所需要的只是前L-1次操作和前R次操作

相当于一个前缀,所以就可以用BIT来维护

每一个BIT来维护的其实就是每一次修改操作之后的权值线段树

这样我们就将修改的时间复杂度压缩为\(O(log_n*log_n)\)

第一个log是BIT,第二个log是权值线段树

相应的,询问操作就要变为\(O(log_n*log_n)\)

因为每到树上一个节点就要用树状数组来算

因为权值线段树上的\(log\)是与整个值域相关的,

所以笔者建议追求极致的Oier们进行离散化

代码

#include<iostream>
#include<algorithm>
#include<climits>
using namespace std;
struct request
{
	int opt;
	int l;
	int r;
	int k;
}q[50005];
struct node
{
	int lson;
	int rson;
	int siz;
}tre[50005<<7];
int n,m;
int cnt;
int tot;
int totx;
int toty;
int a[50005];
int b[100005];
int x[50005];
int y[50005];
int rt[50005];
int lowbit(int x)
{
	return x&(-x);
}
void insert(int &x,int pos,int val,int l=1,int r=cnt)
{
	//cout<<"insert:"<<x<<' '<<pos<<' '<<val<<' '<<l<<' '<<r<<'\n';
	if(!x)
		x=++tot;
	tre[x].siz+=val;
	if(l==r)
		return;
	int mid=(l+r)>>1;
	if(pos<=mid)
		insert(tre[x].lson,pos,val,l,mid);
	else
		insert(tre[x].rson,pos,val,mid+1,r);
}
void modify(int x,int v)
{
	int k=lower_bound(b+1,b+cnt+1,a[x])-b;
	for(int i=x;i<=n;i+=lowbit(i))
		insert(rt[i],k,v);
}
void solve_sum(int &s)
{
	for(int i=1;i<=totx;i++)
		s-=tre[tre[x[i]].lson].siz;
	for(int i=1;i<=toty;i++)
		s+=tre[tre[y[i]].lson].siz;
}
void solve_ls()
{
	for(int i=1;i<=totx;i++)
		x[i]=tre[x[i]].lson;
	for(int i=1;i<=toty;i++)
		y[i]=tre[y[i]].lson;
}
void solve_rs()
{
	for(int i=1;i<=totx;i++)
		x[i]=tre[x[i]].rson;
	for(int i=1;i<=toty;i++)
		y[i]=tre[y[i]].rson;
}
void prepare(int l,int r)
{
	for(int i=l-1;i>0;i-=lowbit(i))
		x[++totx]=rt[i];
	for(int i=r;i>0;i-=lowbit(i))
		y[++toty]=rt[i];
}
int solve_kth(int k,int l=1,int r=cnt)
{
	//cout<<"solve_kth:"<<k<<' '<<l<<' '<<r<<'\n';
	if(l==r)
		return l;
	int mid=(l+r)>>1;
	int s=0;
	solve_sum(s);
	if(k<=s)
	{
		solve_ls();
		return solve_kth(k,l,mid);
	}
	else
	{
		solve_rs();
		return solve_kth(k-s,mid+1,r);
	}
}
void Solve_kth(int l,int r,int k)
{
	totx=toty=0;
	prepare(l,r);
	cout<<b[solve_kth(k)]<<'\n';
}
int solve_rank(int x,int val,int l=1,int r=cnt)
{
	//cout<<"solve_rank:"<<x<<' '<<val<<' '<<l<<' '<<r<<'\n';	
	if(!x)
		return 0;
	if(l==r)
	{
		return 0;
	}
	int mid=(l+r)>>1;
	if(val<=mid)
		return solve_rank(tre[x].lson,val,l,mid);
	else
		return tre[tre[x].lson].siz+solve_rank(tre[x].rson,val,mid+1,r);
}
void Solve_rank(int l,int r,int val)
{
	int s=0;
	int x=lower_bound(b+1,b+cnt+1,val)-b;
	for(int i=l-1;i>0;i-=lowbit(i))
		s-=solve_rank(rt[i],x);
	for(int i=r;i>0;i-=lowbit(i))
		s+=solve_rank(rt[i],x);
	cout<<s+1<<'\n';
}
void solve_pre(int l,int r,int val)
{
	int s=0;
	int x=lower_bound(b+1,b+cnt+1,val)-b;
	for(int i=l-1;i>0;i-=lowbit(i))
		s-=solve_rank(rt[i],x);
	for(int i=r;i>0;i-=lowbit(i))
		s+=solve_rank(rt[i],x);
	if(!s)
		cout<<"-2147483647"<<'\n';
	else
		Solve_kth(l,r,s);
}
void solve_suf(int l,int r,int val)
{
	int s=0;
	int x=lower_bound(b+1,b+cnt+1,val)-b+1;
	for(int i=l-1;i>0;i-=lowbit(i))
		s-=solve_rank(rt[i],x);
	for(int i=r;i>0;i-=lowbit(i))
		s+=solve_rank(rt[i],x);
	if(s>r-l)
		cout<<"2147483647"<<'\n';
	else
		Solve_kth(l,r,s+1);
}
int main()
{
	ios::sync_with_stdio(false);
	//freopen("testdata.in","r",stdin);
	//freopen("ans.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		b[++cnt]=a[i];
	}
	for(int i=1;i<=m;i++)
	{
		cin>>q[i].opt>>q[i].l>>q[i].r;
		if(q[i].opt!=3)
			cin>>q[i].k;
		if(q[i].opt==3)
			b[++cnt]=q[i].r;
		else if(q[i].opt!=2)
			b[++cnt]=q[i].k;
	}
	sort(b+1,b+cnt+1);
	cnt=unique(b+1,b+cnt+1)-b-1;
	for(int i=1;i<=n;i++)
		modify(i,1);
	for(int i=1;i<=m;i++)
	{
		if(q[i].opt==1)
			Solve_rank(q[i].l,q[i].r,q[i].k);
		if(q[i].opt==2)
			Solve_kth(q[i].l,q[i].r,q[i].k);
		if(q[i].opt==3)
		{
			modify(q[i].l,-1);
			a[q[i].l]=q[i].r;
			modify(q[i].l,1);
		}
		if(q[i].opt==4)
			solve_pre(q[i].l,q[i].r,q[i].k);
		if(q[i].opt==5)
			solve_suf(q[i].l,q[i].r,q[i].k);
		//cout<<i<<'\n';
	}
	return 0;
}
posted @ 2019-12-04 21:32  loney_s  阅读(382)  评论(0)    收藏  举报