题意:
给你N个数,然后要你对下面M个查询回答:(L,R,K)。回答第L个数到第R个数之间的第K小数的值是多少。其中任意给定的两个区间[Li,Ri]和[Lj,Rj]之间不存在包含关系。
splay模板题,果然不是自己写的模板就是很多不了解的地方,调试起来贼鸡巴麻烦。
所有的真正的东西都存在结构体里面,查询返回的是离散化后的树上的节点次序。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <utility>
#include <vector>
#include <queue>
#include <map>
#include <set>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 0x3f3f3f3f
#define MAXN 100005
using namespace std;
int cnt,rt;
void init()
{
cnt=1,rt=0;
}
int id[MAXN],res[MAXN];
struct node
{
int l,r,k;
int id;
}s[MAXN];
struct Tree
{
int key,size,fa,son[2],num;
void set(int _key,int _size,int _fa,int _num)
{
key=_key;
size=_size;
fa=_fa;
son[0]=son[1]=0;
num=_num;
}
}T[MAXN];
int cmp(node a,node b)
{
if(a.l==b.l) return a.r>b.r;
else return a.l<b.l;
}
inline void PushUp(int x)
{
T[x].size=T[T[x].son[0]].size+T[T[x].son[1]].size+1;
}
inline void Rotate(int x,int p)
{
int y=T[x].fa;
T[y].son[!p]=T[x].son[p];
T[T[x].son[p]].fa=y;
T[x].fa=T[y].fa;
if(T[x].fa)
T[T[x].fa].son[T[T[x].fa].son[1]==y]=x;
T[x].son[p]=y;
T[y].fa=x;
PushUp(y);
PushUp(x);
}
void Splay(int x,int To)
{
while(T[x].fa!=To) //直到父节点为To
{
if(T[T[x].fa].fa==To) //如果父节点的父节点==To 单旋
Rotate(x,T[T[x].fa].son[0]==x);
else //如果的父节点的父节点!=to 双旋
{
int y=T[x].fa,z=T[y].fa; //y是父节点,z是父节点的父节点
int p=(T[z].son[0]==y);//y是不是在父节点的0路线
if(T[y].son[p]==x) //这里判断是不是和父节点所在路线相反
Rotate(x,!p),Rotate(x,p);// 如果相反 就是之字形
else
Rotate(y,p),Rotate(x,p);//相同 一字型
}
}
if(To==0) rt=x;
}
void Insert(int key,int num)//插入key 并且将该节点转移到根处
{
if(!rt)
T[rt=cnt++].set(key,1,0,num);
else
{
int x=rt,y=0;
while(x)
{
y=x;
x=T[x].son[key>T[x].key];
}
T[x = cnt++].set(key,1,y,num);
T[y].son[key>T[y].key]=x;
Splay(x,0);
}
}
int find(int key)
{
int x=rt;
while(x&&T[x].key!=key)
x=T[x].son[key>T[x].key];
if(x) Splay(x,0);
return x;
}
int GetPth(int p) //获得第p小的节点 并将其转移到根处
{
if(!rt) return 0;
int x=rt,ret=0;
while(x)
{
if(p==T[T[x].son[0]].size+1)
break;
if(p>T[T[x].son[0]].size+1) //判断是第p个是在左边还是右边
{
p-=T[T[x].son[0]].size+1;
x=T[x].son[1];
}
else
x=T[x].son[0];
}
Splay(x,0);
return x;
}
void Delete(int key)//删除值为key的节点 若有重点只删其中一个 x的前驱移动到根处
{
int x=find(key); //找到与key值相同的
if(!x) return ; //如果没有就return
int y=T[x].son[0];
while(T[y].son[1]) //找到左边叶子结点
y=T[y].son[1];
int z=T[x].son[1]; //找到右边叶子结点
while(T[z].son[0])
z=T[z].son[0];
if(!y&&!z) //如果这是根结点
{
rt=0;
return ;
}
if(!y) //只有右叶子结点
{
Splay(z,0);
T[z].son[0]=0;
PushUp(z);
return ;
}
if(!z) //只有左叶子结点
{
Splay(y,0);
T[y].son[1]=0;
PushUp(y);
return ;
}
Splay(y,0);
Splay(z,y);
T[z].son[0]=0;
PushUp(z);
PushUp(y);
}
int main ()
{
int n,m;
while(scanf("%d%d", &n,&m)!=EOF)
{
init();
for(int i=1;i<=n;i++)
scanf("%d",&id[i]);
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&s[i].l,&s[i].r,&s[i].k);
s[i].id=i;
}
sort(s,s+m,cmp);
for(int i=s[0].l;i<=s[0].r;i++)
Insert(id[i],0); //插入需要保留的值。第一个是优先级
//但是在插入后它会进行离散化。这个值会保存在结构体里面
res[s[0].id]=T[GetPth(s[0].k)].key;//由于有离散化 所以返回的是第k个节点
//通过结构体转回值
for(int i=1;i<m;i++)
{
for(int j=s[i-1].l;j<s[i].l;j++)
Delete(id[j]);//删除的是具体值,然后它会找在第几个节点上
if(s[i].r<s[i-1].r)
{
for(int j=s[i].r+1;j<=s[i-1].r;j++)
Delete(id[j]);
}
if(s[i].r>s[i-1].r)
{
for(int j=s[i-1].r+1;j<=s[i].r;j++)
{
Insert(id[j],0);
}
}
res[s[i].id]=T[GetPth(s[i].k)].key;//由于有离散化 所以返回的是第k个节点
//通过结构体转回值
}
for(int i=0;i<m;i++)
printf("%d\n",res[i]);
}
return 0;
}