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]);这个两个小区间合起来就是大区间。所以我们可以通过此种方法进行转移,从而得到每个区间的最值

模板如下:

#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

本题,我们难点在于分情况进行讨论。而且还很多情况,就很恶心。

唉,心累。

本题结合代码进行讲解或许好些

#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;
}

 

posted @ 2020-02-22 01:57  风生  阅读(221)  评论(0编辑  收藏  举报