洛谷 P1533 可怜的狗狗 题解

题目链接

这题很多做法都可以过,这里用的是离线 + 平衡树Treap

题目中:给出的区间不互相包含,是离线操作的一个重要条件

我们将给出的区间按左端点从小到大排序,当左端点相同时,按右端点从小到大排序,满足区间访问的元素位置递增(如果有区间互相包含就无法实现)

对于每一个区间 [ l i , r i ] [l_i,r_i] [li,ri],我们将当前平衡树维护的区间的左右端点进行调整,同时进行插入与删除操作
整体来说并不难

#include 
#include
#include
#include
#include
using namespace std;
const int Maxn=300000+10,inf=0x3f3f3f3f;
struct node{
	int ls,rs,pri,size,val;
	#define ls(x) _node[x].ls
	#define rs(x) _node[x].rs
	#define p(x) _node[x].pri
	#define s(x) _node[x].size
	#define v(x) _node[x].val
}_node[Maxn];
struct seq{
	int l,r,k,pos;
}g[Maxn];
int n,m,root,nodecnt;
int a[Maxn],ans[Maxn];
inline bool cmp(seq x,seq y)
{
	if(x.l==y.l)return x.r<y.r;
	return x.l<y.l;
}
inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
	return s*w;
}
inline void push_up(int &x) 
{
	s(x)=s(ls(x))+s(rs(x))+1;
}
void zag(int &x)
{
	int y=rs(x);
	rs(x)=ls(y);
	ls(y)=x;
	s(y)=s(x);
	push_up(x);
	x=y;
}
void zig(int &x)
{
	int y=ls(x);
	ls(x)=rs(y);
	rs(y)=x;
	s(y)=s(x);
	push_up(x);
	x=y;
}
void ins(int &x,const int k)
{
	if(!x)
	{
		x=++nodecnt,s(x)=1,v(x)=k;
		p(x)=((rand()<<16)+rand())%Maxn;
		ls(x)=rs(x)=0;
		return;
	}
	++s(x);
	if(v(x)>k)
	{
		ins(ls(x),k);
		if(p(ls(x))<p(x))zig(x);
	}
	else
	{
		ins(rs(x),k);
		if(p(rs(x))<p(x))zag(x);
	}
}
void del(int &x,const int k)
{
	if(!x)return;
	if(v(x)==k)
	{
		if(!ls(x) || !rs(x)){x=ls(x)|rs(x);return;}
		if(p(ls(x))<p(rs(x)))zig(x),del(x,k);
		else zag(x),del(x,k);
		return;
	}
	--s(x);
	if(v(x)>k)del(ls(x),k);
	else del(rs(x),k);
}
int find(int k)
{
	int x=root;
	while(x)
	{
		if(k==s(ls(x))+1)return v(x);
		if(k<=s(ls(x)))x=ls(x);
		else k-=s(ls(x))+1,x=rs(x);
	}
	return 0;
}
int main()
{
//	freopen("in.txt","r",stdin);
	srand(time(NULL));
	n=read(),m=read();
	for(int i=1;i<=n;++i)	
	a[i]=read();
	for(int i=1;i<=m;++i)
	{
		g[i].l=read(),g[i].r=read();
		g[i].k=read(),g[i].pos=i;
	}
	sort(g+1,g+1+m,cmp);
	
	int l=g[1].l,r=g[1].l;
	--r;
	for(int i=1;i<=m;++i)
	{
		int x=g[i].l,y=g[i].r,k=g[i].k;
		while(l<x)del(root,a[l]),++l;
		while(r<y)++r,ins(root,a[r]);
		ans[g[i].pos]=find(k);
	}
	for(int i=1;i<=m;++i)	
	printf("%d\n",ans[i]);
	
	return 0;
}

你可能感兴趣的:(题解,#洛谷)