Uva 12299 带循环移动的RMQ(线段树)

题目链接:https://vjudge.net/contest/147973#problem/C

题意:传统的RMQ是一个不变的数组a求区间最值。现在要循环移动(往前移动)。

分析:求区间问题,很容易想到线段树,西东就相当于单点更新。

建树,有两种方案,第一种是nlogn,就是不断的更新,更新logn,有n个数。

 1 #include <bits/stdc++.h>
 2
 3 using namespace std;
 4
 5
 6 const int INF = 1000000000;
 7 const int maxnode = 1<<18;
 8
 9 int op, qL, qR, p, v;   //qL,qR询问区间,p修改点,v修改值
10
11 struct IntervalTree
12 {
13     int minv[maxnode];
14
15     //修改:A[p] = v;
16     void update (int o,int L,int R)
17     {
18         int M = L + (R-L)/2;
19         if(L==R) minv[o] = v;
20         else
21         {
22             if(p<=M) update(o*2,L,M);
23             else update(o*2+1,M+1,R);
24             minv[o] = min(minv[o*2],minv[o*2+1]);
25         }
26     }
27
28     //询问[ql,qr]中的最小值
29     int query(int o,int L,int R)
30     {
31         int M = L+(R-L)/2,ans = INF;
32         if(qL<=L&&R<=qR) return minv[o];
33         if(qL<=M) ans = min(ans,query(o*2,L,M));
34         if(M<qR) ans = min(ans,query(o*2+1,M+1,R));
35         return ans;
36     }
37
38 };
39
40 IntervalTree tree;
41 const int maxn = 100000 + 10;
42 int A[maxn];
43
44 int main()
45 {
46     int n,q;
47     memset(&tree,0,sizeof(tree));
48
49     scanf("%d%d",&n,&q);
50
51     for(p=1; p<=n; p++)
52     {
53         scanf("%d",&v);
54         A[p] = v;
55         tree.update(1,1,n);
56     }
57
58     int k,args[20],original[20];
59     char cmd[100];
60     while(q--)
61     {
62         scanf("%s", cmd);
63         int len = strlen(cmd);
64         k = 0;
65         args[k] = 0;
66         for(int i = 6; i < len; i++)
67         {
68             if(isdigit(cmd[i])) args[k] = args[k] * 10 + cmd[i] - ‘0‘;
69             else
70             {
71                 k++;
72                 args[k] = 0;
73             }
74         }
75         if(cmd[0] == ‘q‘)
76         {
77             qL = args[0];
78             qR = args[1];
79             printf("%d\n", tree.query(1, 1, n));
80         }
81         else
82         {
83             for(int i = 0; i < k; i++) original[i] = A[args[i]];
84             for(int i = 0; i < k; i++)
85             {
86                 p = args[i];
87                 v = A[p] = original[(i+1)%k];
88                 tree.update(1, 1, n);
89             }
90         }
91     }
92     return 0;
93 }

第二种是有一个build的过程,先将数组存起来,然后build,应用到要维护的信息上去。

  1 #include <bits/stdc++.h>
  2
  3 using namespace std;
  4
  5
  6 const int INF = 1000000000;
  7 const int maxnode = 1<<18;
  8
  9 const int maxn = 100000 + 10;
 10 int A[maxn];
 11 int op, qL, qR, p, v;
 12
 13 struct IntervalTree
 14 {
 15     int minv[maxnode];
 16
 17
 18     void build(int o,int L,int R)
 19     {
 20         int M = L + (R-L)/2;
 21         if(L==R) minv[o] = A[L];
 22         else
 23         {
 24             build(o*2,L,M);
 25             build(o*2+1,M+1,R);
 26             minv[o] = min(minv[o*2],minv[o*2+1]);
 27         }
 28     }
 29
 30     //点修改 d[p] =v;
 31     void update(int o,int L,int R)
 32     {
 33         int M = L + (R-L)/2;
 34         if(L==R) minv[o] = v;
 35         else
 36         {
 37             if(p<=M) update(o*2,L,M);
 38             else update(o*2+1,M+1,R);
 39             minv[o] = min(minv[o*2],minv[o*2+1]);
 40         }
 41     }
 42
 43     int query(int o,int L,int R)
 44     {
 45
 46         int M = L + (R-L)/2,ans=INF;
 47         if(qL<=L&&R<=qR)
 48             return minv[o];
 49
 50         if(qL<=M) ans = min(ans,query(o*2,L,M));
 51         if(M<qR) ans = min(ans,query(o*2+1,M+1,R));
 52
 53         return ans;
 54     }
 55
 56 };
 57
 58 IntervalTree tree;
 59
 60 int main()
 61 {
 62     int n,q;
 63     scanf("%d%d",&n,&q);
 64     memset(&tree,0,sizeof(tree));
 65     for(int i=1; i<=n; i++)
 66         scanf("%d",&A[i]);
 67     tree.build(1,1,n);
 68
 69     int k,args[20],original[20];
 70     char cmd[100];
 71     while(q--)
 72     {
 73         scanf("%s", cmd);
 74         int len = strlen(cmd);
 75         k = 0;
 76         args[k] = 0;
 77         for(int i = 6; i < len; i++)
 78         {
 79             if(isdigit(cmd[i])) args[k] = args[k] * 10 + cmd[i] - ‘0‘;
 80             else
 81             {
 82                 k++;
 83                 args[k] = 0;
 84             }
 85         }
 86         if(cmd[0] == ‘q‘)
 87         {
 88             qL = args[0];
 89             qR = args[1];
 90             printf("%d\n", tree.query(1, 1, n));
 91         }
 92         else
 93         {
 94             for(int i = 0; i < k; i++) original[i] = A[args[i]];
 95             for(int i = 0; i < k; i++)
 96             {
 97                 p = args[i];
 98                 v = A[p] = original[(i+1)%k];
 99                 tree.update(1, 1, n);
100             }
101         }
102     }
103     return 0;
104 }
时间: 2024-10-19 04:33:13

Uva 12299 带循环移动的RMQ(线段树)的相关文章

POJ3264 Balanced Lineup RMQ 线段树

求区间内最大数和最小数的差,用两棵线段树,一个维护区间最大值,一个维护区间最小值. #include <stdio.h> #include <vector> #include <math.h> #include <string.h> #include <string> #include <iostream> #include <queue> #include <list> #include <algori

uva 12436 - Rip Van Winkle&#39;s Code(线段树)

题目链接:uva 12436 - Rip Van Winkle's Code 题目大意:四种操作,操作见题目. 解题思路:即用线段树维护一个等差数列,因为一个等差加上一个等差还是一个等差数列,所以对于每个节点记录区 间左端的值,也就是首项,以及公差即可.因为还有一个S操作,所以要开一个标记记录区间值是否相同. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; ty

UVA 12436-Rip Van Winkle&#39;s Code(线段树的区间更新)

题意: long long data[250001]; void A( int st, int nd ) { for( int i = st; i \le nd; i++ ) data[i] = data[i] + (i - st + 1); } void B( int st, int nd ) { for( int i = st; i \le nd; i++ ) data[i] = data[i] + (nd - i + 1); } void C( int st, int nd, int x

poj 3264 Balanced Lineup RMQ线段树实现

Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 36613   Accepted: 17141 Case Time Limit: 2000MS Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer Joh

uva 1400 - &quot;Ray, Pass me the dishes!&quot;(线段树)

题目链接:uva 1400 - "Ray, Pass me the dishes!" 题目大意:给定一个长度为n个整数序列,对m次询问作出回答,对于每次询问(a,b),找到两个下标x,y使得x到y的连续和为区间a,b中最大的连续和,如果存在多解优先x小,然后y小. 解题思路:线段树,对于每个节点维护三个线段值: max_sub:区间连续最大和 max_prefix:区间连续前缀最大和 max_suffix:区间连续后缀最大和 建树的过程维护三个值,查询时只需考虑左右子节点的max_su

codeforces 487B B. Strip(rmq+线段树+二分)

题目链接: codeforces 487B 题目大意: 给出一个序列,要把序列划分成段,每一段最少有L个元素,段中的最大元素和最小元素之差不大于s,问划分的段的最少的数量是多少. 题目分析: 首先用rmq维护区间最大值和区间最小值. 然后按顺序扫描数组,线段树维护的数组,每个记录当前点作为最后一个点的前i个点划分的最小的段数,那么每次更新就是二分找到可以转移到我的最远距离,然后再选取与我距离大于l的那部分,取最小值即可. 最终结果就是线段树维护的数组的最后一个位置的元素的值. AC代码: #in

Uva 1400 &quot;Ray, Pass me the dishes!&quot; ( 线段树 + 区间查询 )

Uva  1400 "Ray, Pass me the dishes!" (线段树 + 区间查询) 题意: 给顶一个长度为n的整数序列D,我们的任务是对m的询问做出回答对于询问(a,b),需要找到两个下标x和y,是的 a <= x <= y <=b并且Dx+...........Dy 尽量大. x,y尽量小 分析: 这题是做线段树比较好的一题,大白书上介绍的是维护了三个域,maxsub,maxpre,maxsuf这里也可以只维护两个域,再最后再考虑跨区间的问题这里没有

[RMQ] [线段树] POJ 3368 Frequent Values

一句话,多次查询区间的众数的次数 注意多组数据!!!! RMQ方法: 预处理 i 及其之前相同的数的个数 再倒着预处理出 i 到不是与 a[i] 相等的位置之前的一个位置, 查询时分成相同的一段和不同的一段 (RMQ) 但是要注意 to[i] 大于查询范围的情况, 以及RMQ时 x < y 的情况!! AC代码: #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib>

UESTC 764 失落的圣诞节 --RMQ/线段树

题意:n种物品,每种物品对不同的人都有不同的价值,有三个人选,第一个为普通学生,第二个是集,第三个是祈,集和祈可以选一样的,并且还会获得加分,集和祈选的普通学生都不能选,问三个人怎样选才能使总分最高. 解法: 先把集和祈选一样的和存到一个数组sum,然后可以枚举普通学生选的是哪个,再在sum的左边和右边找一个最大值,更新Maxi,然后再考虑集祈选的不同的情况,即在集的数组两边取个最大值,以及在祈的数组两边取个最大值,相加即可,如果集的最大值和祈的最大值为一个标记时,我们在前面的sum最大值就已经