ACM: 划分树 poj 2761 在poj2104基…

来源:互联网 发布:mac安装jdk 编辑:程序博客网 时间:2024/06/04 20:30
Feed thedogs

 

Description

Wind loves pretty dogs verymuch, and she has n pet dogs. So Jiajia has to feed the dogs everyday for Wind. Jiajia loves Wind, but not the dogs, so Jiajia use aspecial way to feed the dogs. At lunchtime, the dogs will stand onone line, numbered from 1 to n, the leftmost one is 1, the secondone is 2, and so on. In each feeding, Jiajia choose aninteval[i,j], select the k-th pretty dog to feed. Of course Jiajiahas his own way of deciding the pretty value of each dog. It shouldbe noted that Jiajia do not want to feed any position too much,because it may cause some death of dogs. If so, Wind will be angryand the aftereffect will be serious. Hence any feeding inteval willnot contain another completely, though the intervals may intersectwith each other.

Your task is to help Jiajia calculate which dog ate the food aftereach feeding.

Input

The first line contains n and m,indicates the number of dogs and the number of feedings.

The second line contains n integers, describe the pretty value ofeach dog from left to right. You should notice that the dog withlower pretty value is prettier.

Each of following m lines contain three integer i,j,k, it meansthat Jiajia feed the k-th pretty dog in this feeding.

You can assume that n<100001 andm<50001.

Output

Output file has m lines. Thei-th line should contain the pretty value of the dog who got thefood in the i-th feeding.

Sample Input

7 2
1 5 2 6 3 7 4
1 5 3
2 7 1

Sample Output

3
2

题意: jiajia帮Wind喂狗, 找出区间的第K大元素, 但是此题会有附加出现相同元素.

 

解题思路:

     1. 此题会有附加出现相同元素了, 使用划分树时, 就需要考虑这棵树不要一边倒.

     2. 划分树 同 poj 2104.

      3.怎么让这棵树不一边倒呢?

     平衡划分问题:

        (1). 因为会出现相同元素, 就有可能会有出现, val[deep][i] == a[mid]

        即: 会有出现同中位数相同的值, 如果数量多了, 划分就会偏向左子树.

        (2). Hence, 我们需要统计当前划分树中该层的区间[l,r]中左半部有多少个节点

              等于a[mid]中位数.从而就确定了左半部中位数等于的一部分划分到左子树,

             另外一部分划分到右子树了. 从而使这课树可以平衡些.

 

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
#define MAX 100015

int n, m;
int a[MAX], val[30][MAX], num[30][MAX];
int start, end, k;

int cmp(const void *a, const void *b)
{
 return *(int*)a - *(int*)b;
}

void build_tree(int l, int r, int deep)
{
 if(l == r) return ;
 int mid = (l+r)/2;

 int lsame = mid-l+1;
 for(int i = l; i <= r; ++i)
  if(val[deep][i]< a[mid]) --lsame;
 
 int left_child = l, right_child = mid+1;
 for(int i = l; i <= r; ++i)
 {
  if( (val[deep][i]< a[mid]) || (val[deep][i] == a[mid]&& lsame != 0) )
  {
   if(val[deep][i]== a[mid]) lsame--; //平衡划分
   if(i == l)num[deep][i] = 1;
   elsenum[deep][i] = num[deep][i-1]+1;
   val[deep+1][left_child++]= val[deep][i];
  }
  else
  {
   if(i == l)num[deep][i] = 0;
   elsenum[deep][i] = num[deep][i-1];
   val[deep+1][right_child++]= val[deep][i];
  }
 }
 build_tree(l,mid,deep+1);
 build_tree(mid+1,r,deep+1);
}

int find(int start, int end, int s, int e, int k, intdeep)
{
 if(start == end) return val[deep][start];
 int p, q, mid = (s+e)/2;
 if(start == s) p = 0;
 else p = num[deep][start-1];
 q = num[deep][end];
 int x = q-p;
 if(x >= k)
  return find(s+p, s+q-1, s, mid,k, deep+1);
 else
  return find(mid+start-(s+p)+1,mid+end-(s+q)+1, mid+1, e, k-x, deep+1);
}

int main()
{
// freopen("input.txt","r",stdin);
 while(scanf("%d %d",&n,&m) != EOF)
 {
  for(int i = 1; i<= n; ++i)
  {
   scanf("%d",&a[i]);
   val[0][i] =a[i];
  }
  qsort(a+1,n,sizeof(a[0]),cmp);
  build_tree(1,n,0);
  for(int i = 0; i< m; ++i)
  {
   scanf("%d %d%d",&start, &end,&k);
   int result =find(start, end, 1, n, k, 0);
   printf("%d\n",result);
  }
 }
 return 0;
}

0 0
原创粉丝点击