这道题是要查询某个区间内数字出现的最大次数,序列不降,可以用线段树来做。
每个结点维护左右端点的值和出现次数(长度)以及该区间的Frequent values,然后向上合并即可。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 100001; 7 int a[N]; 8 9 struct Node 10 { 11 int l, r; 12 int lval, rval; 13 int len, llen, rlen; 14 friend Node operator + ( const Node & ln, const Node & rn ) 15 { 16 Node res; 17 res.l = ln.l; 18 res.r = rn.r; 19 res.lval = ln.lval; 20 res.rval = rn.rval; 21 res.llen = ln.llen; 22 if ( ln.lval == ln.rval && ln.rval == rn.lval ) 23 { 24 res.llen += rn.llen; 25 } 26 res.rlen = rn.rlen; 27 if ( ln.rval == rn.lval && rn.lval == rn.rval ) 28 { 29 res.rlen += ln.rlen; 30 } 31 res.len = max( ln.len, rn.len ); 32 if ( ln.rval == rn.lval ) 33 { 34 res.len = max( res.len, ln.rlen + rn.llen ); 35 } 36 return res; 37 } 38 } node[N << 2]; 39 40 void build( int i, int l, int r ) 41 { 42 if ( l == r ) 43 { 44 node[i].l = node[i].r = l; 45 node[i].lval = node[i].rval = a[l]; 46 node[i].len = node[i].llen = node[i].rlen = 1; 47 return ; 48 } 49 int mid = ( l + r ) >> 1; 50 build( i << 1, l, mid ); 51 build( i << 1 | 1, mid + 1, r ); 52 node[i] = node[i << 1] + node[i << 1 | 1]; 53 } 54 55 Node query( int i, int l, int r ) 56 { 57 if ( node[i].l == l && node[i].r == r ) 58 { 59 return node[i]; 60 } 61 int mid = ( node[i].l + node[i].r ) >> 1; 62 if ( r <= mid ) 63 { 64 return query( i << 1, l, r ); 65 } 66 else if ( l > mid ) 67 { 68 return query( i << 1 | 1, l, r ); 69 } 70 else 71 { 72 return query( i << 1, l, mid ) + query( i << 1 | 1, mid + 1, r ); 73 } 74 } 75 76 int main () 77 { 78 int n, m; 79 while ( scanf("%d", &n), n ) 80 { 81 scanf("%d", &m); 82 for ( int i = 1; i <= n; i++ ) 83 { 84 scanf("%d", a + i); 85 } 86 build( 1, 1, n ); 87 while ( m-- ) 88 { 89 int a, b; 90 scanf("%d%d", &a, &b); 91 Node ans = query( 1, a, b ); 92 printf("%d\n", ans.len); 93 } 94 } 95 return 0; 96 }
时间: 2024-11-06 03:47:36