您的位置:首页 > Web前端

poj 2761 Feed the dogs (treap树)

2016-08-13 18:17 441 查看
/*************************************************************
题目:    Feed the dogs(poj 2761)
链接:    http://poj.org/problem?id=2761 题意:    给一个数列,在给一些区间,求这些区间第k小的值,这些
区间没有包含关系,也就是说如果La>Lb那么Ra>Rb;
算法:    treap树
思路:    由于这些区间没有包含关系,把这些区间排序后从左边
开始计算,每计算一个区间把前面多余数删除,这样每
个点只要插入和删除一次就可以了。
**************************************************************/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

const int mx=1000005;
struct S
{
int l, r;
int di,k;
};
S s[mx];
int a[mx];
int ans[mx];
int n,m;
bool com(S a,S b)
{
if (a.l==b.l) return a.r<b.r;
return a.l<b.l;
}

typedef struct Node    ///节点的结构体
{
Node *l,*r;
int val,pri;      ///节点的值和优先级
int sz;           ///节点子树的节点数
Node(int x)       ///初始化节点
{
l=r=NULL;
val=x;
pri=rand();
sz=1;
}
}Node;
Node *root;

int Tsize(Node *T)  ///计算子树的叶子节点
{
if (T==NULL) return 0;
return T->sz;
}
Node *L_rotate(Node *T)    ///右节点的优先级大于当前节点的优先级,进行左旋转
{
Node *A=T->r;         ///A表示有节点
T->r=A->l;
A->l=T;
A->sz-T->sz;         ///交换后A变成当前节点,所以它的子树的节点数等于原来节点的节点数
T->sz=Tsize(T->l)+Tsize(T->r)+1;
return A;
}
Node *R_rotate(Node *T)   ///左节点的优先级大于当前节点的优先级,进行右旋转
{
Node *A=T->l;
T->l=A->r;
A->r=T;
A->sz=T->sz;
T->sz=Tsize(T->l)+Tsize(T->r)+1;
return A;
}

void inser(Node *&T,int val) ///插入函数,和二叉排序树差不多
{
if (T==NULL)
{
T=new Node(val);
return ;
}
if (T->val>=val)
{
inser(T->l,val);
if ((T->l->pri)<(T->pri)) T=R_rotate(T); ///优先级比较,并旋转
}
else
{
inser(T->r,val);
if ((T->r->pri)<(T->pri)) T=L_rotate(T);
}
T->sz=Tsize(T->l)+Tsize(T->r)+1;
}

void Delete(Node *&T,int val)        ///删除函数
{
if (T->val>val) Delete(T->l,val);
else if (T->val<val) Delete(T->r,val);
else
{
if (T->l==NULL&&T->r==NULL) T=NULL;   ///左右节点都为空
else if (T->r==NULL) T=T->l;          ///右节点为空
else if(T->l==NULL) T=T->r;           ///左节点为空
else                                  ///左右都不空
{
if (T->l->pri<T->r->pri)          ///左节点优先级小于右边
{                                 ///右旋转,并向右子树删除
T=R_rotate(T);                ///应为有旋转后,要删除的节点到有子树去了
Delete(T->r,val);
}
else
{
T=L_rotate(T);
Delete(T->l,val);
}
}
}
if (T!=NULL)
{
T->sz=Tsize(T->l)+Tsize(T->r)+1;
}
}

int Find(Node *T,int k)                      ///查找第k小的树
{
int temp=Tsize(T->l)+1;                  ///temp小于等于T->val数的个数
if (temp==k) return T->val;
if (temp>k) return Find(T->l,k);
return Find(T->r,k-temp);
}

void solve()
{
sort(s+1,s+m+1,com);
s[0].l=-1;
s[0].r=-2;
for (int i=1;i<=m;i++)
{
for (int j=s[i-1].l;j<=min(s[i-1].r,s[i].l-1);j++)
Delete(root,a[j]);    ///删除比要计算区间多的数
for (int j=max(s[i-1].r+1,s[i].l);j<=s[i].r;j++)
inser(root,a[j]);     ///插入该区间剩下的数
ans[s[i].di]=Find(root,s[i].k);
}
for (int j=s[m].l;j<=s[m].r;j++) Delete(root,a[j]);
}

int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=m;i++)
{
int l,r;
scanf("%d%d%d",&l,&r,&s[i].k);
s[i].l=min(l,r);
s[i].r=max(l,r);
s[i].di=i;
}
root=NULL;
solve();
for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: