模板之st表
题意:
给出n个数字与q组询问,每次询问一个区间[l,r]的最小值与最大值。
首先,此题可用线段树保存最大值和最小值。。。但是因为没有修改,所以用一些更简单的数据结构即可
st表的功能:nlogn的时间预处理每个点为端点2^x长度的区间信息,然后就可以在O(1)的时间内完成询问。
mn数组的意义在于保存区间的长度,stmin与stmax来保存最大值与最小值。
每次以i为端点更新左右2^j长度的区间信息,注意先枚举j。
比较以l为左端点与以r为右端点的区间信息,回答询问。
#include<cstdio> int stmax[100005][20],stmin[100005][20]; int a[100005],mn[100005]; int t,q,n,l,r; int max(int x,int y) { if(x>y) return x; else return y; } int min(int x,int y) { if(x<y) return x; else return y; } int main() { scanf("%d",&n);scanf("%d",&q); for(int i=1;i<=n;i++) scanf("%d",&a[i]); mn[0]=-1; for(int i=1;i<=n;i++) { if((i&(i-1))==0) mn[i]=mn[i-1]+1; else mn[i]=mn[i-1]; stmax[i][0]=a[i]; stmin[i][0]=a[i]; } for(int j=1;j<=mn[n];j++) { for(int i=1;i+(1<<j)<=n+1;i++) { stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<j-1)][j-1]); stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<j-1)][j-1]); } } while(q--) { scanf("%d %d",&l,&r); int k=mn[r-l+1]; printf("%d ",min(stmin[l][k],stmin[r-(1<<k)+1][k])); printf("%d\n",max(stmax[l][k],stmax[r-(1<<k)+1][k])); } return 0; }