POJ_3368 Frequent values 【线段树+区间查询】

一、题面

POJ3368

二、分析

仍然是一道只需要区间查询不需要区间修改的线段树题。

这题的题面比较特别,它是一组非减的数组。当需要去找一段区间内出现次数最多的数字时,这些数字必然是连续的,那么就可以用线段树维护区间内出现的最大次数时,同时维护两端的数字出现的次数。这样,就可以在建树的时候通过判断可能的左右子树最大值和(左子树的最右端的数的次数+右子树的最左端的数的次数),括号出现的前提是左子树维护的区间右端点的数与右子树维护的区间左端点的数相等。

保证建树建成功后,就是基本的查询了,但是需要注意的是,当mid在要查询的区间内时,因为查询的区间跨了线段树的两个区间,所以当左子树维护的右端点的值和右子树的左端点的值相等时,需要与当前最大值进行比较。

二刷这题后,补充一下,初始化的问题,每组样例过后,记得对线段树的一些标记是改变了的。

三、AC代码

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <algorithm>
  5 
  6 using namespace std;
  7 
  8 const int MAXN = 1e5;
  9 
 10 struct Node
 11 {
 12     int l, r;
 13     int cntl, cntr, Max;
 14 }segTree[MAXN<<2];
 15 int Data[MAXN], Ans;
 16 
 17 void Build(int v, int L, int R)
 18 {
 19     segTree[v].l = L;
 20     segTree[v].r = R;
 21     if(L == R)
 22     {
 23         segTree[v].Max = 1;
 24         segTree[v].cntl = segTree[v].cntr = 1;
 25         return;
 26     }
 27     int mid = (L + R) >> 1;
 28     int lc = v<<1, rc = v<<1|1;
 29     Build(lc, L, mid);
 30     Build(rc, mid + 1, R);
 31     int sum = 0;        //初始化别忘了
 32     if(Data[segTree[lc].r] == Data[segTree[rc].l])
 33     {
 34         sum = segTree[lc].cntr + segTree[rc].cntl;
 35     }
 36     if(segTree[lc].Max > segTree[rc].Max)
 37         segTree[v].Max = segTree[lc].Max;
 38     else
 39         segTree[v].Max = segTree[rc].Max;
 40     segTree[v].Max = max(segTree[v].Max, sum);
 41     segTree[v].cntl = segTree[lc].cntl;
 42     segTree[v].cntr = segTree[rc].cntr;
 43     if(Data[segTree[v].l] == Data[segTree[rc].l])
 44     {
 45         segTree[v].cntl += segTree[rc].cntl;
 46     }
 47     if(Data[segTree[v].r] == Data[segTree[lc].r])
 48     {
 49         segTree[v].cntr += segTree[lc].cntr;
 50     }
 51 }
 52 
 53 void Query(int v, int L, int R)
 54 {
 55     if(Ans >= segTree[v].Max)
 56         return;
 57     if(segTree[v].l == L && segTree[v].r == R)
 58     {
 59         Ans = max(Ans, segTree[v].Max);
 60         return;
 61     }
 62     int mid = (segTree[v].l + segTree[v].r)>>1;
 63     if(L > mid)
 64     {
 65         Query(v<<1 | 1, L, R);
 66     }
 67     else if(R <= mid)
 68     {
 69         Query(v<<1, L, R);
 70     }
 71     else
 72     {
 73         Query(v<<1, L, mid);
 74         Query(v<<1 | 1, mid + 1, R);
 75         int temp = 0;
 76         if(Data[mid] == Data[mid + 1])
 77         {
 78             temp = min(segTree[v<<1].cntr, mid - L + 1);
 79             //为什么要考虑mid-L+1,因为可能所插叙的区间并没有完全包含所有的这个数
 80             temp += min(segTree[v<<1|1].cntl, R - mid);
 81         }
 82         Ans = max(Ans, temp);
 83     }
 84 }
 85 
 86 int main()
 87 {
 88     //freopen("input.txt", "r", stdin);
 89     int N, Q;
 90     while(scanf("%d", &N) == 1 && N)
 91     {
 92         scanf("%d", &Q);
 93         int L, R;
 94         for(int i = 1; i <= N; i++)
 95             scanf("%d", &Data[i]);
 96         Build(1, 1, N);
 97         for(int i = 0; i < Q; i++)
 98         {
 99             Ans = -MAXN;
100             scanf("%d %d", &L, &R);
101             Query(1, L, R);
102             printf("%d\n", Ans);
103         }
104     }
105 }

 

posted @ 2019-03-22 21:40  Dybala21  阅读(190)  评论(0编辑  收藏  举报