Uva 12299 带循环移动的RMQ(线段树)
Posted 树的种子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于Uva 12299 带循环移动的RMQ(线段树)的主要内容,如果未能解决你的问题,请参考以下文章
UVa 12299 RMQ with Shifts(移位RMQ)