POJ 3368 Frequent values RMQ / 线段树

来源:互联网 发布:压缩文件加密破解软件 编辑:程序博客网 时间:2024/05/19 03:43

题意;给定一个升序的数列(1-100000), 比如 array[10] =  -1  -1  1  1  1  1  3  10  10  10, 求其中某段区间上相同的数字最多有几个。[ 2, 3 ] = 1, [ 1, 10 ] = 4, [ 5, 10 ] = 3。(下标从1开始)。

题解:先将连续相等的几个数合并为一个部分(part), 或者说一个点。每点包括了起始位置,终止位置,相等元素个数三个信息。
            查询的时候需要整点的查询,假设对区间 [ a, b ] 查询 ( [ a, b ] 里可能包含了多个点 ), 若 a, b 均不是点的边界位置,那么就需要进行处理。
            例如前面的数列求 [ 5, 10 ], 我们已经知道 { -1, -1 } = 点 1, { 1,1,1,1 } = 点2, { 3 } = 点3, { 10,10,10 } = 点4。array[5]属于点2但不是点的边界,那么将 5 - 6 取出来单独讨论,然后再查询点3,点4。

#include <iostream>using namespace std;#define N 1000000#define M 100005int array[M], hash[M];/* hash表示每一个数字所属的part */struct partition{int s, t, cnt;} part[M];struct item{int l, r, num;} node[N];int max ( int a, int b ){return a > b ? a : b;}void build_tree ( int l, int r, int u ){node[u].l = l;node[u].r = r;if ( l == r ){node[u].num = part[l].cnt;return;}int mid = ( l + r ) / 2;build_tree ( l, mid, u * 2 );build_tree ( mid + 1, r, u * 2 + 1 );node[u].num = max ( node[u*2].num, node[u*2+1].num );}int query ( int l, int r, int u ){if ( node[u].l == l && node[u].r == r )return node[u].num;int mid = ( node[u].l + node[u].r ) / 2;if ( r <= mid )return query ( l, r, u * 2 );else if ( l > mid )return query ( l, r, u * 2 + 1 );elsereturn max ( query(l,mid,u*2), query(mid+1,r,u*2+1) );}int main(){int n, q;int i, id, a, b, num1, num2, num3;//freopen("a.txt","r",stdin);while ( scanf("%d",&n) && n ){scanf("%d",&q);for ( i = 1; i <= n; ++i )scanf("%d",&array[i]);memset(part,0,sizeof(part));part[1].s = id = 1;for ( i = 1; i <= n; ++i ) / *离散化,连续相同的数字归为一个part */{part[id].cnt++;hash[i] = id;if ( array[i] != array[i+1] || i == n ){part[id].t = i;id++;part[id].s = i+1;}}build_tree ( 1, id - 1, 1 );while ( q-- ){scanf("%d%d",&a,&b);if ( hash[a] == hash[b] )printf("%d\n",b-a+1);else{num1 = part[ hash[a] ].t - a + 1;num2 = b - part[ hash[b] ].s + 1;num3 = 0;if ( hash[b] - hash[a] > 1 )    num3 = query ( hash[a] + 1, hash[b] - 1, 1 );printf("%d\n", max( max(num1,num2), num3 ) );}}}return 0;}


RMQ解法:

#include <cmath>#include <iostream>using namespace std;#define M 100010int array[M], hash[M];int dp[M][18];struct partition{int s, t, cnt;} part[M];int max ( int a, int b ){return a > b ? a : b;}void Dpmax ( int n )  {      int i, j, temp;      for ( i = 1; i <= n; ++i )          dp[i][0] = part[i].cnt;      temp = log(n+1.0)/log(2.0);      for ( i = 1; i <= temp; ++i )          for ( j = 1; j + (1<<i) - 1 <= n; ++j )              dp[j][i] = max ( dp[j][i-1], dp[j+(1<<(i-1))][i-1] );  } int getmax ( int a, int b )  {      int k = (int)( log(b-a+1.0) / log(2.0) );      return max ( dp[a][k], dp[b-(1<<k)+1][k] );  } int main(){int n, q;int i, id, a, b, num1, num2, num3;//freopen("a.txt","r",stdin);while ( scanf("%d",&n) && n ){scanf("%d",&q);for ( i = 1; i <= n; ++i )scanf("%d",&array[i]);memset(part,0,sizeof(part));part[1].s = id = 1;for ( i = 1; i <= n; ++i ){part[id].cnt++;hash[i] = id;if ( array[i] != array[i+1] || i == n ){part[id].t = i;id++;part[id].s = i+1;}}Dpmax(id-1);while ( q-- ){scanf("%d%d",&a,&b);if ( hash[a] == hash[b] )printf("%d\n",b-a+1);else{num1 = part[ hash[a] ].t - a + 1;num2 = b - part[ hash[b] ].s + 1;num3 = 0;if ( hash[b] - hash[a] > 1 )    num3 = getmax ( hash[a] + 1, hash[b] - 1 );printf("%d\n", max( max(num1,num2), num3 ) );}}}return 0;}



原创粉丝点击