【模板】可持久化线段树 2

就是区间第k大,原题链接
这个是用整体二分做的

这个是用可持久化线段树做的

线段树还是快一点啊

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
	char c=getchar();ll a=0,b=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
struct Segment{
	ll lc,rc,cnt;
}tr[5000001];
ll n,m,a[2000001],tot,cnt,changed,b[2000001],root[5000001],c[2000001];
map<ll,ll> ma;
ll build(ll l,ll r)
{
	ll p=++tot;
	if(l==r)
	{
		tr[p].cnt=0;
		return p;
	}
	ll mid=l+r>>1;
	tr[p].lc=build(l,mid);
	tr[p].rc=build(mid+1,r);
	tr[p].cnt=tr[tr[p].lc].cnt+tr[tr[p].rc].cnt;
	return p;
}
ll insert(ll now,ll l,ll r,ll x,ll val)
{
	ll p=++tot;
	tr[p]=tr[now];
	if(l==r)
	{
		tr[p].cnt+=val;
		return p;
	}
	ll mid=l+r>>1;
	if(x<=mid)tr[p].lc=insert(tr[now].lc,l,mid,x,val);
	else tr[p].rc=insert(tr[now].rc,mid+1,r,x,val);
	tr[p].cnt=tr[tr[p].lc].cnt+tr[tr[p].rc].cnt;
	return p;
}
ll ask(ll now1,ll now2,ll l,ll r,ll k)
{
	if(l==r)return a[l];
	ll mid=l+r>>1;
	ll lcnt=tr[tr[now1].lc].cnt-tr[tr[now2].lc].cnt;
	if(k<=lcnt)return ask(tr[now1].lc,tr[now2].lc,l,mid,k);
	else return ask(tr[now1].rc,tr[now2].rc,mid+1,r,k-lcnt);
}
int main()
{
//	freopen("2.in","r",stdin);
//	freopen("2.out","w",stdout);
	n=read(),m=read();
	for(ll i=1;i<=n;i++)
		b[i]=a[i]=read();
	sort(a+1,a+1+n);
	int ned=0;ned=1;
	for(int i=2;i<=n;i++)
	{
		if(a[i]!=a[i-1])a[++ned]=a[i];
	}
	for(ll i=1;i<=ned;i++)
		ma[a[i]]=++cnt;
	for(int i=1;i<=n;i++)
	{
		b[i]=ma[b[i]];
//		cout<<b[i]<<' ';
	}
//	cout<<endl;
//	sort(b+1,b+1+n);
	for(ll i=1;i<=n;i++)
	{
		root[i]=insert(root[i-1],1,cnt,b[i],1);
	}
	for(ll i=1;i<=m;i++)
	{
		ll l=read(),r=read(),k=read();
		cout<<ask(root[r],root[l-1],1,cnt,k)<<endl;
	}
	return 0;
}
/*
5 2
1 1 3 2 2
1 3 2
3 5 2

*/
posted @ 2024-01-26 14:00  HL_ZZP  阅读(3)  评论(0编辑  收藏  举报