poj 2761 feeding the dog (splay树 模板)

题意:

    给你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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值