区间的连续段~ST表(模板题)
链接:https://www.nowcoder.com/acm/contest/82/B
来源:牛客网
时间限制:C/C++ 7秒,其他语言14秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给你一个长为n的序列a和一个常数k
有m次询问,每次查询一个区间[l,r]内所有数最少分成多少个连续段,使得每段的和都 <= k
如果这一次查询无解,输出"Chtholly"
输入描述:
第一行三个数n,m,k
第二行n个数表示这个序列a
之后m行,每行给出两个数l r表示一次询问
输出描述:
输出m行,每行一个整数,表示答案
示例1
输入
5 5 7 2 3 2 3 4 3 3 4 4 5 5 1 5 2 4
输出
1 1 1 2 2
备注:
对于100%的数据,1 <= n , m <= 1000000 , 1 <= ai , k <= 1000000000
这题需要用到倍增算法,倍增博大精深啊。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstring> 6 #include<queue> 7 using namespace std; 8 9 const int maxn =1e6+10; 10 typedef long long ll; 11 ll sum[maxn],f[maxn][22]; 12 13 int main() { 14 ll n,m,k; 15 scanf("%lld%lld%lld",&n,&m,&k); 16 for (int i=1 ;i<=n ;i++){ 17 ll x; 18 scanf("%lld",&x); 19 sum[i]=sum[i-1]+x; 20 } 21 for (int i=0 ;i<=21 ;i++ ) f[n+1][i]=n+1; 22 for (int i=n ;i>=1 ;i-- ) { 23 f[i][0]=upper_bound(sum+i,sum+n+1,sum[i-1]+k)-sum; 24 for (int j=1 ;j<=21 ;j++) { 25 f[i][j]=f[f[i][j-1]][j-1]; 26 } 27 } 28 while(m--){ 29 ll x,y,ans=0; 30 scanf("%lld%lld",&x,&y); 31 for (int i=21 ;i>=0 ;i--){ 32 if (f[x][i]<=y) ans+=1<<i,x=f[x][i]; 33 } 34 if (f[x][0]>y) printf("%lld\n",ans+1); 35 else printf("Chtholly\n"); 36 } 37 return 0; 38 }