1 /*************************************************************
  2 题目:    Feed the dogs(poj 2761)
  3 链接:    http://poj.org/problem?id=2761
  4 题意:    给一个数列,在给一些区间,求这些区间第k小的值,这些
  5           区间没有包含关系,也就是说如果La>Lb那么Ra>Rb;
  6 算法:    treap树
  7 思路:    由于这些区间没有包含关系,把这些区间排序后从左边
  8           开始计算,每计算一个区间把前面多余数删除,这样每
  9           个点只要插入和删除一次就可以了。
 10 **************************************************************/
 11 #include<cstdio>
 12 #include<cstring>
 13 #include<algorithm>
 14 #include<iostream>
 15 using namespace std;
 16 
 17 const int mx=1000005;
 18 struct S
 19 {
 20     int l, r;
 21     int di,k;
 22 };
 23 S s[mx];
 24 int a[mx];
 25 int ans[mx];
 26 int n,m;
 27 bool com(S a,S b)
 28 {
 29     if (a.l==b.l) return a.r<b.r;
 30     return a.l<b.l;
 31 }
 32 
 33 typedef struct Node    ///节点的结构体
 34 {
 35     Node *l,*r;
 36     int val,pri;      ///节点的值和优先级
 37     int sz;           ///节点子树的节点数
 38     Node(int x)       ///初始化节点
 39     {
 40         l=r=NULL;
 41         val=x;
 42         pri=rand();
 43         sz=1;
 44     }
 45 }Node;
 46 Node *root;
 47 
 48 int Tsize(Node *T)  ///计算子树的叶子节点
 49 {
 50     if (T==NULL) return 0;
 51     return T->sz;
 52 }
 53 Node *L_rotate(Node *T)    ///右节点的优先级大于当前节点的优先级,进行左旋转
 54 {
 55     Node *A=T->r;         ///A表示有节点
 56     T->r=A->l;
 57     A->l=T;
 58     A->sz-T->sz;         ///交换后A变成当前节点,所以它的子树的节点数等于原来节点的节点数
 59     T->sz=Tsize(T->l)+Tsize(T->r)+1;
 60     return A;
 61 }
 62 Node *R_rotate(Node *T)   ///左节点的优先级大于当前节点的优先级,进行右旋转
 63 {
 64     Node *A=T->l;
 65     T->l=A->r;
 66     A->r=T;
 67     A->sz=T->sz;
 68     T->sz=Tsize(T->l)+Tsize(T->r)+1;
 69     return A;
 70 }
 71 
 72 void inser(Node *&T,int val) ///插入函数,和二叉排序树差不多
 73 {
 74     if (T==NULL)            
 75     {
 76         T=new Node(val);
 77         return ;
 78     }
 79     if (T->val>=val)
 80     {
 81         inser(T->l,val);
 82         if ((T->l->pri)<(T->pri)) T=R_rotate(T); ///优先级比较,并旋转
 83     }
 84     else
 85     {
 86         inser(T->r,val);
 87         if ((T->r->pri)<(T->pri)) T=L_rotate(T);
 88     }
 89     T->sz=Tsize(T->l)+Tsize(T->r)+1;   
 90 }
 91 
 92 void Delete(Node *&T,int val)        ///删除函数
 93 {
 94     if (T->val>val) Delete(T->l,val);
 95     else if (T->val<val) Delete(T->r,val);
 96     else
 97     {
 98         if (T->l==NULL&&T->r==NULL) T=NULL;   ///左右节点都为空
 99         else if (T->r==NULL) T=T->l;          ///右节点为空
100         else if(T->l==NULL) T=T->r;           ///左节点为空
101         else                                  ///左右都不空
102         {
103             if (T->l->pri<T->r->pri)          ///左节点优先级小于右边
104             {                                 ///右旋转,并向右子树删除
105                 T=R_rotate(T);                ///应为有旋转后,要删除的节点到有子树去了
106                 Delete(T->r,val);
107             }
108             else
109             {
110                 T=L_rotate(T);
111                 Delete(T->l,val);
112             }
113         }
114     }
115     if (T!=NULL)
116     {
117         T->sz=Tsize(T->l)+Tsize(T->r)+1;
118     }
119 }
120 
121 int Find(Node *T,int k)                      ///查找第k小的树
122 {
123     int temp=Tsize(T->l)+1;                  ///temp小于等于T->val数的个数
124     if (temp==k) return T->val;
125     if (temp>k) return Find(T->l,k);
126     return Find(T->r,k-temp);
127 }
128 
129 
130 void solve()
131 {
132     sort(s+1,s+m+1,com);
133     s[0].l=-1;
134     s[0].r=-2;
135     for (int i=1;i<=m;i++)
136     {
137         for (int j=s[i-1].l;j<=min(s[i-1].r,s[i].l-1);j++)
138         Delete(root,a[j]);    ///删除比要计算区间多的数
139         for (int j=max(s[i-1].r+1,s[i].l);j<=s[i].r;j++) 
140         inser(root,a[j]);     ///插入该区间剩下的数
141         ans[s[i].di]=Find(root,s[i].k);
142     }
143     for (int j=s[m].l;j<=s[m].r;j++) Delete(root,a[j]);
144 }
145 
146 int main()
147 {
148      scanf("%d%d",&n,&m);
149      for (int i=1;i<=n;i++) scanf("%d",&a[i]);
150      for (int i=1;i<=m;i++)
151      {
152          int l,r;
153          scanf("%d%d%d",&l,&r,&s[i].k);
154          s[i].l=min(l,r);
155          s[i].r=max(l,r);
156          s[i].di=i;
157      }
158      root=NULL;
159      solve();
160      for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
161 }

 

posted on 2016-08-13 18:17  pb2016  阅读(212)  评论(0编辑  收藏  举报