1. 程式人生 > >POJ_3368 Frequent values 【線段樹+區間查詢】

POJ_3368 Frequent values 【線段樹+區間查詢】

-s 區間修改 pri clas 兩個 成功 區間 printf turn

一、題面

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 }

POJ_3368 Frequent values 【線段樹+區間查詢】