ST表
ST表主要用于区间最值操作。更准确的说,应该是用于可重复贡献
比如区间最小值,最大值。
我们先来看一道模板题:
https://www.luogu.com.cn/problem/P3865
1,暴力超时。线段树可行。
2,我们用st表。
我们定义f[N][21];f[i][j]表示的是区间[i,i+(1<<j)-1]这个区间的最大值。
我们可以如何通过小区间来转移得到大区间呢?
我们发现f[i][j]=max(f[i][j-1],f[i+(1<<j)][j-1]);这个两个小区间合起来就是大区间。所以我们可以通过此种方法进行转移,从而得到每个区间的最值
模板如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #include"stdio.h" #include"string.h" #include"math.h" #include"algorithm" using namespace std; const int N = 100100; int n,m; int a[N],f[N][30]; ///表示的是下标为[i,i + 2^j-1]这个区间最大值 int Logn[N]; void pre() { Logn[1] = 0; Logn[2] = 1; for ( int i = 3; i < N; i++) { Logn[i] = Logn[i / 2] + 1; } } int main() { scanf ( "%d%d" ,&n,&m); for ( int i = 1; i <= n; i ++) { scanf ( "%d" ,&a[i]); f[i][0] = a[i]; } for ( int j = 1; j <= 21; j ++) { for ( int i = 1;i + (1 << j) - 1 <= n; i ++) { f[i][j] = max(f[i][j - 1],f[i + (1 << (j - 1))][j - 1]); } } pre(); while (m -- ) { int l,r; scanf ( "%d%d" ,&l,&r); int s = Logn[r - l + 1]; int maxx = max(f[l][s],f[r - (1 << s) + 1][s]); printf ( "%d\n" ,maxx); } } |
进阶题:https://www.luogu.com.cn/problem/P2471
本题,我们难点在于分情况进行讨论。而且还很多情况,就很恶心。
唉,心累。
本题结合代码进行讲解或许好些
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | #include"stdio.h" #include"string.h" #include"math.h" #include"algorithm" using namespace std; const int N = 50100; inline int read() { char c = getchar (); int x = 0, f = 1; while (c < '0' || c > '9' ) { if (c == '-' ) f = -1; c = getchar (); } while (c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar (); } return x * f; } int n,m; int a[N],f[N][30]; ///表示的是下标为[i,i + 2^j-1]这个区间最大值 int Logn[N]; int year[N]; void pre() { Logn[1] = 0; Logn[2] = 1; for ( int i = 3; i < N; i++) { Logn[i] = Logn[i / 2] + 1; } } int main() { n = read(); for ( int i = 1; i <= n; i ++) { year[i] = read(); f[i][0] = read(); } for ( int j = 1; j <= 21; j++) for ( int i = 1; i + (1 << j) - 1 <= n; i++) f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); m = read(); pre(); while (m -- ) { int l,r;l = read(); r = read(); if (l == r) ///如果输入的是相同年份,那一定是true { printf ( "true\n" ); continue ; } int id1 = lower_bound(year + 1,year + n + 1,l) - year; int id2 = lower_bound(year + 1,year + n + 1,r) - year; if (id1 == id2){ ///如果年份不相同,但是查找下表相同,那我们肯定一定是maybe。这几种情况可以画画就知道了。 printf ( "maybe\n" ); continue ; } if (year[id1] == l && year[id2] == r){ ///l和r都存在的情况 if (f[id1][0] < f[id2][0]) { ///如果r的值大于l年份的值,那一定是false。根据题目定义可得。 printf ( "false\n" ); continue ; } if (id1 + 1 == id2){ ///如果他们之间只相差一个单位 if (r - l + 1 == 2 && f[id2][0] <= f[id1][0]) { ///如果r的值小于等于l地方的值,则一定为true。 printf ( "true\n" ); } else { printf ( "maybe\n" ); } continue ; } int x = id1 + 1,y = id2 - 1; int s = Logn[y - x + 1]; int maxx = max(f[x][s], f[y - (1 << s) + 1][s]); ///查找id1+1,id2-1这个区间的最值。因为+1,-1,的缘故,所以我们在上面就特判了相差一个单位的情况。 if (maxx < f[id2][0]){ if (id2 - id1 + 1 == r - l + 1) printf ( "true\n" ); else printf ( "maybe\n" ); } else printf ( "false\n" ); } else if (year[id1] != l && year[id2] != r){ ///l和r都不存在的情况 printf ( "maybe\n" ); } else if (year[id1] == l){ ///仅l存在的情况 if (id1 + 1 == id2){ printf ( "maybe\n" ); continue ; } int x = id1 + 1,y = id2 - 1; int s = Logn[y - x + 1]; int maxx = max(f[x][s], f[y - (1 << s) + 1][s]); if (f[id1][0] <= maxx) printf ( "false\n" ); else printf ( "maybe\n" ); continue ; } else if (year[id2] == r) { ///仅r存在的情况 if (id1 + 1 == id2){ if (f[id1][0] < f[id2][0]) ///这里是个坑点,注意l的值是没有的,id1位置的值是比l大,那么这个值小于r值,那一定是有可能的。这个我没考虑到。 printf ( "maybe\n" ); else printf ( "false\n" ); continue ; } int x = id1,y = id2 - 1; int s = Logn[y - x + 1]; int maxx = max(f[x][s], f[y - (1 << s) + 1][s]); if (f[id2][0] > maxx) printf ( "maybe\n" ); else printf ( "false\n" ); } } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!