ST表poj3264
/* ST表多次查询区间最小值 设 g[j][i] 表示从第 i 个数到第 i + 2 ^ j - 1 个数之间的最小值 类似DP的说 ans[i][j]=min (ans[i][mid],ans[mid+1][r])mid=(l+r)/2 but 数太大装不下 所以改一个g数组出来就好了 接下来考虑 g[i][j]由谁转移来(不漏下就好 因为是去min 可以重复 同理gcd也可以 其他的就要考虑考虑了) 解决方案是搞一个p[i] 表示长度为i的区间长度是2的p[i]次方(下取整) 那么, ans[l][r]就可以不漏的表示为 min(g[w][l],g[w][r-(1<<w)+1]) (w=p[l-r+1]) */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 200010 using namespace std; int n,m,a[maxn],g[21][maxn],p[maxn],f[21][maxn]; int init() { int x=0; int f=0; char s; s=getchar(); while(s<'0'||s>'9') { if(s=='-')f=1; s=getchar(); } while(s>='0'&&s<='9') { x=x*10+s-'0'; s=getchar(); } if(f==0)return x; else return -x; } void slove() { int i,j; for(i=1;i<=n;i++) { g[0][i]=a[i]; f[0][i]=a[i]; } for(i=1;i<=18;i++) for(j=0;j+(1<<i>>1)<=n;j++) g[i][j]=min(g[i-1][j],g[i-1][j+(1<<i>>1)]); for(i=1;i<=18;i++) for(j=0;j+(1<<i>>1)<=n;j++) f[i][j]=max(f[i-1][j],f[i-1][j+(1<<i>>1)]); memset(p,-1,sizeof(p)); for(i=0;i<18;i++) p[1<<i]=i; for(i=0;i<maxn;i++) if(p[i]==-1) p[i]=p[i-1]; } int find1(int l,int r) { int w=p[r-l+1]; return max(f[w][l],f[w][r-(1<<w)+1]); } int find2(int l,int r) { int w=p[r-l+1]; return min(g[w][l],g[w][r-(1<<w)+1]); } int main() { n=init();m=init(); int i,l,r; for(i=1;i<=n;i++) a[i]=init(); slove(); for(i=1;i<=m;i++) { l=init();r=init(); if(l>r)swap(l,r); cout<<find1(l,r)-find2(l,r)<<endl; } return 0; }