Uva 11235 RMQ问题

RMQ:

有一个不变的数组,不停的求一个区间的最小值。

使用倍增的思想优化到logN;

d(i,j) 表示从 i 开始的,长度为2j的一段元素中的最小值。

那么状态转移方程:

d(i,j) = min{ d(i,j-1) ,  d(i+2j-1,j-1) } 

题目链接:https://vjudge.net/contest/146667#problem/B

题意:一个非降序的数组,询问(i,j)中出现次数最多的数值,所对应的出现次数是多少。

分析:

进行游戏编码,value[i] 和count[i] 表示第 i 段对应的数值和出现的次数,

num[i] 表示位置 i 对应的段所在的编号,left[i] 表示 i 位置所在的段的左端点,right[i] 右端点。

那么(L,R)就是分成3个部分。

一个是right[L] - L + 1,R-left[R] + 1,还一个就是RMQ(count,num[L]+1,num[R]-1)。

特殊情况:如果L和R在同一段里面,R-L+1;

Source Code:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<vector>
 4 using namespace std;
 5 
 6 const int maxn = 100000 + 5;
 7 const int maxlog = 20;
 8 
 9 // 区间最*大*值
10 struct RMQ
11 {
12     int d[maxn][maxlog];
13     void init(const vector<int>& A)
14     {
15         int n = A.size();
16         for(int i = 0; i < n; i++) d[i][0] = A[i];
17         for(int j = 1; (1<<j) <= n; j++)
18             for(int i = 0; i + (1<<j) - 1 < n; i++)
19                 d[i][j] = max(d[i][j-1], d[i + (1<<(j-1))][j-1]);
20     }
21 
22     int query(int L, int R)
23     {
24         int k = 0;
25         while((1<<(k+1)) <= R-L+1) k++; // 如果2^(k+1)<=R-L+1,那么k还可以加1
26         return max(d[L][k], d[R-(1<<k)+1][k]);
27     }
28 };
29 
30 int a[maxn], num[maxn], left[maxn], right[maxn];
31 RMQ rmq;
32 
33 
34 int main()
35 {
36     int n,q;
37     while(scanf("%d%d",&n,&q)==2)
38     {
39         for(int i=0; i<n; i++)
40             scanf("%d",&a[i]);
41 
42         a[n] = a[n-1] + 1;
43         int start = -1;
44         vector<int> count;
45         for(int i=0; i<=n; i++)
46         {
47             if(i==0||a[i]>a[i-1])
48             {
49                 if(i>0)
50                 {
51                     count.push_back(i-start);
52                     for(int j=start;j<i;j++) {
53                         num[j] = count.size()-1;
54                         left[j] = start;
55                         right[j] = i-1;
56                     }
57                 }
58                 start = i;
59             }
60         }
61 
62         rmq.init(count);
63         while(q--) {
64             int L,R,ans;
65             scanf("%d%d",&L,&R);
66             L--;
67             R--;
68             if(num[L]==num[R]) ans = R - L + 1;
69             else {
70                 ans = max(R-left[R]+1,right[L]-L+1);
71                 if(num[L]+1<num[R])
72                     ans = max(ans,rmq.query(num[L]+1,num[R]-1));
73             }
74             printf("%d\n",ans);
75         }
76     }
77     return 0;
78 }
View Code

 

转载于:https://www.cnblogs.com/TreeDream/p/6297798.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值