ACM: 线段树 poj 3368

来源:互联网 发布:java回退流 编辑:程序博客网 时间:2024/09/21 09:27
Frequent values
Description

You are given a sequence of n integersa1 , a2 , ... ,an in non-decreasing order. In addition tothat, you are given several queries consisting of indicesi and j (1 ≤ i ≤ j ≤ n).For each query, determine the most frequent value among theintegers ai , ... , aj.

Input

The input consists of several test cases. Each test case startswith a line containing two integers n andq (1 ≤ n, q ≤ 100000). The next linecontains n integers a1 , ... ,an (-100000 ≤ ai ≤ 100000,for each i ∈ {1, ..., n}) separated by spaces. You canassume that for each i ∈ {1, ..., n-1}: ai ≤ai+1. The following q lines containone query each, consisting of two integers i andj (1 ≤ i ≤ j ≤ n), which indicate theboundary indices for the
query.

The last test case is followed by a line containing a single0.

Output

For each query, print one line with one integer: The number ofoccurrences of the most frequent value within the given range.

Sample Input

10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0

Sample Output

1
4
3

 

题意: 给定一个长度为n的序列, 有m次访问一个区间中, 出现最多的元素的次数.

 

解题思路:

    1. 多次访问某个区间的问题, 一般用线段树来做. 题目给一段已经按照升序的序列, 需要先离散化.

        线段树每个节点需要设置2个域,num:计算在原序列中的位置, count: 当前val值得元素个数.

        离散化之后建立一棵线段树,插入元素相应的统计在每个段中的最多的元素. 用样例如图:

        ACM: <wbr>线段树 <wbr>poj <wbr>3368

    2.显然, [0,3]区间的count = 4, [0,1]区间的count = 4, [2,3]区间的count = 3, ...,以此类推

       这是线段树离散化的建立,剩下的问题就是怎么查询:

       (1).其实问题可以简化为一个:就是如果要查询原序列[5,10]时(从下标1开始), 怎么将图中(1)段

           计算出2个1.想一想可以发现, 当用二分查找的时候, 查找到相应的段时, p->left ==p->right

          记录想要查找的原序列区间[l, r]的count = (r-l+1); 这样处理在一个段中的问题了. 剩下跟一

          般线段树搜索一样了.

 

代码:

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

struct Node
{
 int count, num;//count:相应val值个数, num: 原序列序号
 int val;
}p[MAX];

struct node
{
 int l, r;
 int count, num;
 int val;
}pt[MAX*2];

int n, m;
int A, B;

inline int max(int a, int b)
{
 return a > b ? a : b;
}

inline int min(int a, int b)
{
 return a < b ? a : b;
}

void buildTree(int l, int r, int pos)
{
 pt[pos].l = l, pt[pos].r = r;
 pt[pos].count = pt[pos].num = 0;
 pt[pos].val =-(1<<30);
 if(l == r) return ;
 int mid = (l+r)/2;
 buildTree(l, mid, pos*2);
 buildTree(mid+1, r, pos*2+1);
}

void insert(Node &a, int index, int pos)
{
 if(a.count > pt[pos].count)
 {
  pt[pos].count = a.count;
  pt[pos].val = a.val;
 }
 if(pt[pos].l == pt[pos].r) return ;
 int mid = (pt[pos].l+pt[pos].r)/2;
 if(index <= mid)
  insert(a, index, pos*2);
 else
  insert(a, index,pos*2+1);
}

void find(int l, int r, Node &a, int pos)
{
 int ll, rr;
 if(pt[pos].l == 0) ll = 1;
 else ll = p[ pt[pos].l-1 ].num+1;//当前区间的第一个序号
 rr = p[ pt[pos].r ].num;

 if(l == ll &&r == rr)
 {
  a.count = pt[pos].count;
  a.val = pt[pos].val;
  return ;
 }

 if(pt[pos].l == pt[pos].r)
 {
  a.count = r-l+1;
  a.val = pt[pos].val;
  return ;
 }

 Node lside, rside;
 lside.count = rside.count = 0;
 int mid = (pt[pos].l+pt[pos].r)/2;
 if(l <= p[mid].num)
  find(l, min(p[mid].num, r),lside, pos*2);
 if(r > p[mid].num)
  find(max(p[mid].num+1, l), r,rside, pos*2+1);
 if(lside.count >rside.count)
 {
  a.count = lside.count;
  a.val = lside.val;
 }
 else
 {
  a.count = rside.count;
  a.val = rside.val;
 }
}

int main()
{
 int i, j, t;
// freopen("input.txt","r",stdin);
 while(scanf("%d",&n) !=EOF)
 {
  if(n == 0) break;
  elsescanf("%d",&m);

  scanf("%d",&p[0].val);
  p[0].num = p[0].count =1;
  j = 0;
  for(i = 1; i <n; ++i)
  {
   scanf("%d",&t);
   if(t ==p[j].val)
   {
    p[j].num++;
    p[j].count++;
   }
   else
   {
    j++;
    p[j].count= 1;
    p[j].num= p[j-1].num+1;
    p[j].val= t;
   }
  }
  n = j;

  buildTree(0, n, 1);//总共区间变成了0~n了
  for(i = 0; i <=n; ++i)
   insert(p[i],i, 1);

  for(i = 0; i< m; ++i)
  {
   scanf("%d%d",&A, &B);
   Nodetemp;
   find(A, B,temp, 1);
   printf("%d\n",temp.count);
  }
 }
 return 0;
}

 

0 0