题目描述
给你一个长为n的序列a和一个常数k
有m次询问,每次查询一个区间[l,r]内所有数最少分成多少个连续段,使得每段的和都 <= k
如果这一次查询无解,输出"Chtholly"
输入描述:
第一行三个数n,m,k
第二行n个数表示这个序列a
之后m行,每行给出两个数l r表示一次询问
输出描述:
输出m行,每行一个整数,表示答案
输入
5 5 7 2 3 2 3 4 3 3 4 4 5 5 1 5 2 4
输出
1 1 1 2 2
sol:初看以为是线段树题,但是肯定会被卡。 我们用st表预处理,st[i][j]表示i点右移1<<j刀的最远距离。 和求LCA的道理一样,只要没到达边界,贪就完事了。
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1000010; ll a[maxn]; int st[maxn][21],lg[maxn]; int main() { int N,M,K,L,R,pos,res; scanf("%d%d%d",&N,&M,&K); rep(i,1,N) lg[i]=lg[i>>1]+1; rep(i,1,N) scanf("%lld",&a[i]); rep(i,1,N) a[i]+=a[i-1]; rep(i,0,20) st[N+1][i]=N+1; for(int i=N;i>=1;i--){ pos=upper_bound(a+1,a+N+1,a[i-1]+K)-a; st[i][0]=pos; rep(j,1,20) st[i][j]=st[st[i][j-1]][j-1]; } rep(i,1,M){ scanf("%d%d",&L,&R); pos=L; res=0; for(int j=lg[R-L+1];j>=0;j--) { if(st[pos][j]<=R) pos=st[pos][j],res+=(1<<j); } if(st[pos][0]<=R) puts("Chtholly"); else printf("%d\n",res+1); } return 0; }