[其他ST产品] C++ ST表

[复制链接]
499|7
 楼主| 个百zz分点个 发表于 2023-4-21 23:33 | 显示全部楼层 |阅读模式
RMQ 问题
        RMQ(Range Minimum/Maximum Query)问题是指:对于长度为 n 的数列 A,回答若干询问 RMQ  (区间 [ l,r ] ) ,返回数列A中下标在 l , r 里的最小/大值,也就是说,RMQ 问题是指求区间最值的问题。

ST 表
        st 表和线段树常被用来解决 RMQ 问题,两个各有优缺点:st 表运行效率高,但不能修改;线段树运行效率相对较慢,但支持修改操作。

        st 表的合并复杂度为 O(1),构建复杂度为 O(n log n),查询复杂度是 O(1)。

        st 表的核心要领在于倍增和 DP ,设区间左端点为 l ,长度为  ,求其区间最值。st 表的做法就是 DP 预处理出所有的区间最值,询问时直接输出。

42366442acbb7da9e.png

其中 merge 为最值函数,最大值用 max ,最小值用 min 。

        易看出,只有当区间中重叠的部分对最终答案无影响时,才能使用 st 表。

        一点小优化,可以预处理一个 log[] 数组,以减小 cmath 库中 函数的运算时间。


评论

———————————————— 版权声明:本文为CSDN博主「允彦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/struct_GS/article/details/120747242  发表于 2023-4-21 23:33
 楼主| 个百zz分点个 发表于 2023-4-21 23:34 | 显示全部楼层
log 函数预处理
        没什么可讲的,只是注意初始时,log [0] = -1 。因为 log 和 某个函数重了,所以用 Log 来表示。

  1. for(register int i=1;i<=n;i++)
  2.     Log[i]=Log[i>>1]+1;
 楼主| 个百zz分点个 发表于 2023-4-21 23:34 | 显示全部楼层
例题讲解
P3865 【模板】ST 表https://www.luogu.com.cn/problem/P3865

https://www.luogu.com.cn/problem/P3865
 楼主| 个百zz分点个 发表于 2023-4-21 23:35 | 显示全部楼层
st 表的板子题目,也可以用线段树,不过需要卡常。

st 表做法:

        套用 st 表的板子,轻松 AC ,时间复杂度为 O(n log n + m) 。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<algorithm>
  5. #include<map>
  6. #include<vector>
  7. #include<string>
  8. #include<cstring>
  9. #include<queue>
  10. #include<stack>
  11. using namespace std;
  12. inline int read()
  13. {
  14.     int num=0,w=1;
  15.     char ch=getchar();
  16.     while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
  17.     while(ch>='0'&&ch<='9') {num=(num<<1)+(num<<3)+ch-'0';ch=getchar();}
  18.     return num*w;
  19. }
  20. int n,m,l,r,k;
  21. int a[100001];
  22. int f[100001][30];
  23. int Log[100001];
  24. inline void st()
  25. {
  26.         Log[0]=-1;
  27.         for(register int i=1;i<=n;i++) Log[i]=Log[i>>1]+1;
  28.         for(register int i=1;i<=n;i++) f[i][0]=a[i];
  29.         for(register int j=1;j<=Log[n];j++)
  30.                 for(register int i=1;i+(1<<j)-1<=n;i++)
  31.                         f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
  32.         return;
  33. }
  34. int main()
  35. {
  36.         //freopen(".in","r",stdin);
  37.         //freopen(".out","w",stdout);
  38.         n=read(),m=read();
  39.         for(register int i=1;i<=n;i++) a[i]=read();
  40.         st();
  41.         while(m--)
  42.         {
  43.                 l=read(),r=read();
  44.                 k=Log[r-l+1];
  45.                 printf("%d\n",max(f[l][k],f[r-(1<<k)+1][k]));}
  46.         //fclose(stdin);
  47.         //fclose(stdout);               
  48.         return 0;
  49. }
 楼主| 个百zz分点个 发表于 2023-4-21 23:35 | 显示全部楼层
线段树做法:

        需要使用卡常**!!!

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<queue>
  5. #include<map>
  6. #include<vector>
  7. #include<string>
  8. #include<cstring>
  9. #include<stack>
  10. using namespace std;
  11. inline int read()
  12. {
  13.         int num=0,w=1;
  14.         char ch=getchar();
  15.         while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
  16.         while(ch>='0'&&ch<='9') {num=(num<<1)+(num<<3)+ch-'0';ch=getchar();}
  17.         return num*w;
  18. }
  19. struct node
  20. {
  21.         int l;
  22.         int r;
  23.         int maxx;
  24. }tree[1000001];
  25. int n,m,x,y;
  26. int a[1000001];
  27. inline void add(int k)
  28. {
  29.         tree[k].maxx=max(tree[k<<1].maxx,tree[k<<1|1].maxx);
  30. }
  31. inline void build(int k,int l,int r)
  32. {
  33.         tree[k].l=l,tree[k].r=r;
  34.         if(l==r) {tree[k].maxx=a[l];return;}
  35.         int mid=(l+r)>>1;
  36.         build(k<<1,l,mid);
  37.         build(k<<1|1,mid+1,r);
  38.         add(k);
  39.         return;
  40. }
  41. inline int find(int k,int l,int r,int x,int y)
  42. {
  43.         if(x<=l&&r<=y) return tree[k].maxx;
  44.         int mid=(l+r)>>1;
  45.         int res=-0x3f3f3f;
  46.         if(x<=mid) res=max(res,find(k<<1,l,mid,x,y));
  47.         if(y>mid) res=max(res,find(k<<1|1,mid+1,r,x,y));
  48.         return res;
  49. }
  50. int main()
  51. {
  52.         n=read(),m=read();
  53.         for(register int i=1;i<=n;i++) a[i]=read();
  54.         build(1,1,n);
  55.         while(m--)
  56.         {
  57.                 x=read(),y=read();
  58.                 printf("%d\n",find(1,1,n,x,y));
  59.         }
  60.         return 0;
  61. }
Clyde011 发表于 2024-6-6 07:08 | 显示全部楼层

电源电压处于1.6V到5.5V之间
公羊子丹 发表于 2024-6-6 08:01 | 显示全部楼层

电压范围称为工作电源电压
公羊子丹 发表于 2024-6-6 08:01 | 显示全部楼层

电压范围称为工作电源电压
万图 发表于 2024-6-6 09:04 | 显示全部楼层

内部电路工作电圧是通过内部电压调节器调节电源电压得到的
Uriah 发表于 2024-6-6 10:07 | 显示全部楼层

单片机的外部都连接有象电池等电源部分
帛灿灿 发表于 2024-6-6 12:03 | 显示全部楼层

通常选择0.01μF~0.1μF的陶瓷电容作为旁路电容。
Bblythe 发表于 2024-6-6 13:06 | 显示全部楼层

主时钟振荡器主要用作CPU的工作时钟
周半梅 发表于 2024-6-6 15:02 | 显示全部楼层

防止因瞬间大电流引起的电源电压下降
Pulitzer 发表于 2024-6-6 16:05 | 显示全部楼层

要在外部连接一个振荡电路提供时钟信号
童雨竹 发表于 2024-6-6 18:01 | 显示全部楼层

与15号引脚连接的C1称为旁路电容
Wordsworth 发表于 2024-6-6 19:04 | 显示全部楼层

时序电路是按时钟信号(CK)的上升沿(信号从L→H的变化)或下降沿(信号从H→L的变化)同步工作的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

53

主题

679

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0