st表

 学习了这篇📕,然后结合学长教的。

 一、一维st表:

       用st[i][j]表示从i开始,1 << j 个连续数的最值; 设我们求某一区间的最值,则可拆分成这个区间前半区间和后半区间的最值,然后再继续拆,就很logn了。 然后写的时候就先给st[i][0]赋a[i],然后从小区间到大区间循环,把st“neng”上去,注意是j套i(因为要确保判断的st要处理过,处理的st[i+(1<<(j-1))][j-1]的那一块,j套i在上一次就遍历过,如果i套j的话前面部分还没),还要判断i+(1<<(j-1))是否超过n,不然没意义了~ 所以预处理的复杂度是O(nlogn)

     而询问也联系拆成一半的思路,还要知道一个(化简就出来)的定理:2^log(a)>a/2 。我们查 l - r 的最值,区间长度是 len=r-l+1,令 t = log(len) ,则 2^t>len/2 ;

     所以可以想象得到 l + 2^t 超过了区间的一半 ,r - 2^t +1 也超过了一半, 这两部分合起来比较最值就得到了,所以询问的复杂度是O(1)!,想象一下veen图的形状~ 然后就是酱 

 1 int st[N][20],a[N];
 2 void findm()
 3 {
 4     for(int i=0;i<n;i++) {st[i][0]=a[i];}
 5     for(int j=1;j<20;j++)
 6         for(int i=0;i<n;i++)
 7            if(i+(1<<(j-1))<n)
 8              st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
 9 }
10 int query(int l,int r)
11 {
12     int len=log2(r-l+1);
13     return min(st[l][len],st[r-(1<<len)+1][len]);
14 }

🎈有一道板子题 poj-3264 Balanced Lineup //如果log2用不了,就写 floor(log10(r-l+1)/log10(2)) 好了 

 1 //#include<bits/stdc++.h>
 2 #include<iostream>
 3 #include<stack>
 4 #include<algorithm>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<cstring>
 8 #define mem(a) memset(a,0,sizeof(a))
 9 #define ll long long
10 #define mp make_pair
11 #define inf 0x3f3f3f3f
12 const int N=2e5+5;
13 const int M=1e3+10;
14 const ll lim=1e14+5;
15 using namespace std;
16 int n,top=0,m;
17 int st[N][20],stmx[N][20],a[N];
18 void findm()
19 {
20     for(int i=0;i<n;i++) {st[i][0]=a[i];stmx[i][0]=a[i];}
21 
22     for(int j=1;j<20;j++)
23         for(int i=0;i<n;i++)
24            if(i+(1<<(j-1))<n)
25              st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
26 
27     for(int j=1;j<20;j++)
28         for(int i=0;i<n;i++)
29            if(i+(1<<(j-1))<n)
30              stmx[i][j]=max(stmx[i][j-1],stmx[i+(1<<(j-1))][j-1]);
31 
32 }
33 int query(int l,int r)
34 {
35     int len=log2(r-l+1);
36    // cout<<"***"<<len;
37     int mna=min(st[l][len],st[r-(1<<len)+1][len]);
38     int mxa=max(stmx[l][len],stmx[r-(1<<len)+1][len]);
39     //cout<<"***"<<mxa<<"***"<<mna<<endl;
40     return mxa-mna;
41 }
42 int main()
43 {
44     scanf("%d%d",&n,&m);
45     for(int i=0;i<n;i++)
46            scanf("%d",&a[i]);
47 
48     findm();
49     int l,r;
50     while(m--)
51     {
52 
53         scanf("%d%d",&l,&r);
54         printf("%d\n",query(l-1,r-1));
55     }
56     return 0;
57 }
poj 3264-st表
 1 //#include<bits/stdc++.h>
 2 #include<iostream>
 3 #include<stack>
 4 #include<algorithm>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<cstring>
 8 #define mem(a) memset(a,0,sizeof(a))
 9 #define memm(a) memset(a,inf,sizeof(a))
10 #define ll long long
11 #define ld long double
12 #define uL unsigned long long
13 #define mp make_pair
14 #define pb push_back
15 #define inf 0x3f3f3f3f
16 using namespace std;
17 const int N=1e6+5;
18 const int M=100+5;
19 int n,s,k,x[N],y[N],z[N];
20 int a[N],treemax[4*N],treemin[4*N],lazy[4*N];
21 void push_up(int rt)
22 {
23     treemax[rt]=max(treemax[rt],max(treemax[rt<<1],treemax[rt<<1|1]));
24     treemin[rt]=min(treemin[rt],min(treemin[rt<<1],treemin[rt<<1|1]));
25 }
26 
27 void build(int rt,int l,int r)
28 {
29     if(l==r)
30     {
31         treemax[rt]=max(a[l],treemax[rt]);
32         treemin[rt]=min(a[l],treemin[rt]);
33         return;
34     }
35     int mid=(l+r)>>1;
36     build(rt<<1,l,mid);
37     build(rt<<1|1,mid+1,r);
38     push_up(rt);
39 }
40 
41 int querymax(int L,int R,int rt,int l,int r)
42 {
43     if(L<=l&&r<=R) return treemax[rt];
44     int mid=(l+r)>>1;
45     int ans=0;
46     if(L<=mid) ans=max(ans,querymax(L,R,rt<<1,l,mid));
47     if(R>mid) ans=max(ans,querymax(L,R,rt<<1|1,mid+1,r));
48     return ans;
49 }
50 int querymin(int L,int R,int rt,int l,int r)
51 {
52     if(L<=l&&r<=R) return treemin[rt];
53     int mid=(l+r)>>1;
54     int ans=inf;
55     if(L<=mid) ans=min(ans,querymin(L,R,rt<<1,l,mid));
56     if(R>mid) ans=min(ans,querymin(L,R,rt<<1|1,mid+1,r));
57     return ans;
58 }
59 int main()
60 {
61     scanf("%d%d",&n,&k);
62     for(int i=1;i<=n;i++)
63         scanf("%d",&a[i]);
64     for(int i=1;i<=4*n;i++)
65         treemax[i]=0,treemin[i]=inf;
66     build(1,1,n);
67     int l,r;
68     while(k--)
69     {
70         scanf("%d%d",&l,&r);
71         int mx=querymax(l,r,1,1,n),mn=querymin(l,r,1,1,n);
72        // cout<<"---"<<mx<<"---"<<mn<<endl;
73         printf("%d\n",mx-mn);
74     }
75    return 0;
76 }
poj 3264-线段树

 二、二维st表:

跟一维思想差不多,就是变成了矩形,这样一个大矩形就拆分成四个小的矩形 (差不多这个样子),然后这四个取最值就好 --》 max(max(,),max(,))

//这个是三维的(正方形)

 1 int stm[300][300][20],a[300][300];
 2 void findm()
 3 {
 4     for(int i=1;i<=n;i++)
 5         for(int j=1;j<=n;j++)
 6             stm[i][j][0]=stn[i][j][0]=a[i][j];
 7     for(int k=1;k<20;k++)
 8         for(int i=1;i<=n;i++)
 9             for(int j=1;j<=n;j++)
10                 if((i+(1<<(k-1)))<=n && (j+(1<<(k-1)))<=n)
11                     stm[i][j][k]=max(max(stm[i][j][k-1],stm[i+(1<<(k-1))][j+(1<<(k-1))][k-1]),
12                                      max(stm[i][j+(1<<(k-1))][k-1],stm[i+(1<<(k-1))][j][k-1])),
13 }
14 int query(int l,int r,int k)
15 {
16     int len=log2(k); //k >= 1<<len
17     return max(max(stm[l][r][len],stm[l+k-(1<<len)][r+k-(1<<len)][len]),
18                max(stm[l][r+k-(1<<len)][len],stm[l+k-(1<<len)][r][len]));
19 }

🎈二维板子题: poj-2019 Cornfields   //正好2019欸,好巧~

 1 //#include<bits/stdc++.h>
 2 #include<iostream>
 3 #include<stack>
 4 #include<algorithm>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<cstring>
 8 #define mem(a) memset(a,0,sizeof(a))
 9 #define ll long long
10 #define mp make_pair
11 #define inf 0x3f3f3f3f
12 const int N=2e5+5;
13 const int M=1e3+10;
14 const ll lim=1e14+5;
15 using namespace std;
16 int n,top=0,m;
17 int stm[300][300][20],stn[300][300][20],a[300][300];
18 void findm()
19 {
20     for(int i=1;i<=n;i++)
21         for(int j=1;j<=n;j++)
22             stm[i][j][0]=stn[i][j][0]=a[i][j];
23     for(int k=1;k<20;k++)
24         for(int i=1;i<=n;i++)
25             for(int j=1;j<=n;j++)
26                 if((i+(1<<(k-1)))<=n && (j+(1<<(k-1)))<=n)
27                     stm[i][j][k]=max(max(stm[i][j][k-1],stm[i+(1<<(k-1))][j+(1<<(k-1))][k-1]),
28                                      max(stm[i][j+(1<<(k-1))][k-1],stm[i+(1<<(k-1))][j][k-1])),
29                     stn[i][j][k]=min(min(stn[i][j][k-1],stn[i+(1<<(k-1))][j+(1<<(k-1))][k-1]),
30                                      min(stn[i][j+(1<<(k-1))][k-1],stn[i+(1<<(k-1))][j][k-1]));
31 }
32 int query(int l,int r,int k)
33 {
34     int len=log2(k); //k >= 1<<len
35     int mx=max(max(stm[l][r][len],stm[l+k-(1<<len)][r+k-(1<<len)][len]),
36                max(stm[l][r+k-(1<<len)][len],stm[l+k-(1<<len)][r][len]));
37     int mi=min(min(stn[l][r][len],stn[l+k-(1<<len)][r+k-(1<<len)][len]),
38                min(stn[l][r+k-(1<<len)][len],stn[l+k-(1<<len)][r][len]));
39     return mx-mi;
40 }
41 int main()
42 {
43     int l,r,k;
44     while(~scanf("%d%d%d",&n,&k,&m)){
45     mem(stm);mem(stn);
46     for(int i=1;i<=n;i++)
47         for(int j=1;j<=n;j++)
48            scanf("%d",&a[i][j]);
49     findm();
50     while(m--)
51     {
52         scanf("%d%d",&l,&r);
53         printf("%d\n",query(l,r,k));
54     }
55   }
56     return 0;
57 }
poj 2019 -- st表

 还有一个四维的矩形题 hdoj-2888 Check Corners :

算是模板题了吧,思路还是一样的。这里n宽m长,k是从i开始宽为1<<k。关键是k和kk是从0开始,因为要考虑第一行和第一列的情况,然后判断k是否为0,为0则单独考虑第一行情况。st表示从左上角开始的矩形最大值。

//不晓得三维用一个个正方形比较哪里错了o(TヘTo) 。

 1 #include<iostream>
 2 #include<stack>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<cstring>
 7 #define mem(a) memset(a,0,sizeof(a))
 8 #define ll long long
 9 #define mp make_pair
10 #define inf 0x3f3f3f3f
11 const int N=3e2+5;
12 const int M=1e3+10;
13 const ll lim=1e14+5;
14 using namespace std;
15 int  n,m,a[N][N],st[N][N][9][9],lens ;
16 void findm()
17 {
18     for(int k=0;(1<<k)<=n;k++)
19        for(int kk=0;(1<<kk)<=m;kk++)
20         {
21             if(k==0&&kk==0) continue;
22             for(int i=1;i<=n;i++)
23               for(int j=1;j<=m;j++)
24                 if(i+(1<<(k-1))<=n&&j+(1<<(kk-1))<=m)
25                   {
26                       if(k)
27                       st[i][j][k][kk]=max(st[i][j][k-1][kk],st[i+(1<<(k-1))][j][k-1][kk]);
28                       else
29                       st[i][j][k][kk]=max(st[i][j][k][kk-1],st[i][j+(1<<(kk-1))][k][kk-1]);                  }
30         }
31 
32 }
33 int query(int x1,int y1,int x2,int y2)
34 {
35     int lenx=log2(x2-x1+1),leny=log2(y2-y1+1);
36     return max(max(st[x1][y1][lenx][leny],st[x2+1-(1<<lenx)][y2+1-(1<<leny)][lenx][leny]),
37                max(st[x2+1-(1<<lenx)][y1][lenx][leny],st[x1][y2+1-(1<<leny)][lenx][leny]));
38 
39 }
40 int main()
41 {
42     while(~scanf("%d%d",&n,&m))
43     {
44         for(int i=1;i<=n;i++)
45             for(int j=1;j<=m;j++)
46                 {scanf("%d",&a[i][j]);st[i][j][0][0]=a[i][j];}
47         findm();
48         int x1,y2,y1,x2,q;
49         scanf("%d",&q);
50         while(q--)
51         {
52             scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
53             int ans=query(x1,y1,x2,y2);
54             if(ans==a[x1][y1]||ans==a[x1][y2]||ans==a[x2][y1]||ans==a[x2][y2])
55                 printf("%d yes\n",ans);
56             else printf("%d no\n",ans);
57         }
58     }
59      return 0;
60 }
hdoj-2888

 

 三、题目

POJ 3368 Frequent values

 题意:求一段区间内出现次数最多的数(不过好像没说次数一样的//或者我看漏了~)因为数是从小到大排的,所以就比较简单了。之前分块入门9,呜呼。用st表的话,就要维护一个最值,这题求众数,那st数组就存自己从开始到现在(这个下标)出现了几次,然后取大就好了。但是因为是某一区间,所以就这样会有错误,要判断[l,r]前后会不会有跟边界的点一样的数,这样就再来一个数组co,存这个数出现的最右边的位置。如果a[l]=a[l-1],那就要判断r是否小于co[l],这样就分成两种。①这一区间内所有值都是a[l],这样直接r-l+1;②前半段是a[l],后半段是其他,那就先看后半段的最大值,最后跟co[l]-l+1比较大小。  

 1 //#include<bits/stdc++.h>
 2 
 3 #include<iostream>
 4 #include<stack>
 5 #include<algorithm>
 6 #include<cstdio>
 7 #include<cmath>
 8 #include<cstring>
 9 #define mem(a) memset(a,0,sizeof(a))
10 #define ll long long
11 #define mp make_pair
12 #define inf 0x3f3f3f3f
13 const int N=1e5+5;
14 const int M=1e3+10;
15 const ll lim=1e14+5;
16 using namespace std;
17 int n,top=0,m;
18 int st[N][20],co[N],a[N];
19 
20 void findm()
21 {
22     int id=1;
23     a[0]=-N,co[n]=n;
24     for(int i=1;i<=n;i++)
25     {
26         if(a[i]!=a[i-1])
27         {
28            id=1;
29            st[i][0]=id;
30         }
31         else
32         {
33             st[i][0]=++id;
34         }
35     }
36     for(int i=n-1;i>=1;i--)
37     {
38         if(a[i]==a[i+1]) co[i]=co[i+1];
39         else co[i]=i;
40     }
41     // for(int i=1;i<=n;i++)
42      //   cout<<"**"<<st[i][0]<<endl;
43     for(int j=1;j<20;j++)
44         for(int i=1;i<=n;i++)
45           if(i+(1<<(j-1))<=n)
46            {
47                st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
48               // cout<<"st["<<i<<"]["<<j<<"]= "<<st[i][j]<<endl;
49            }
50 
51 }
52 int query(int l,int r)
53 {
54     int ans=0,k=l; 
55     if(co[l]==co[l-1]) k=min(co[l],r)+1; 
56     int len=log2(r-k+1);
57     if(k<=r)
58     ans=max(st[k][len],st[r-(1<<len)+1][len]);
59     return max(ans,k-l);
60 }
61 int main()
62 {
63     int l,r;
64     while(~scanf("%d%d",&n,&m)&&n){
65     mem(st);
66     for(int i=1;i<=n;i++)
67            scanf("%d",&a[i]);
68     findm();
69     while(m--)
70     {
71         scanf("%d%d",&l,&r);
72         printf("%d\n",query(l,r));
73     }
74   }
75     return 0;
76 }
poj3368-st表

 

posted @ 2019-07-14 15:33  XXrl  阅读(661)  评论(0编辑  收藏  举报