题目描述

给你一个长为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=;
ll a[maxn]; int st[maxn][],lg[maxn];
int main()
{
int N,M,K,L,R,pos,res;
scanf("%d%d%d",&N,&M,&K);
rep(i,,N) lg[i]=lg[i>>]+;
rep(i,,N) scanf("%lld",&a[i]);
rep(i,,N) a[i]+=a[i-];
rep(i,,) st[N+][i]=N+;
for(int i=N;i>=;i--){
pos=upper_bound(a+,a+N+,a[i-]+K)-a;
st[i][]=pos;
rep(j,,) st[i][j]=st[st[i][j-]][j-];
}
rep(i,,M){
scanf("%d%d",&L,&R);
pos=L; res=;
for(int j=lg[R-L+];j>=;j--) {
if(st[pos][j]<=R) pos=st[pos][j],res+=(<<j);
}
if(st[pos][]<=R) puts("Chtholly");
else printf("%d\n",res+);
}
return ;
}

来自WXK更加NB的做法,目前时间上RK1。

先不考虑K的限制:对于每个点L,我们找到右边界R,[L,R),连边L->R,表示从L出发,最多走到R-1,下一步的起点是R。 然后倒着建树,父亲唯一的,对应的是下一步。   得到dep,得到dfs序。  那么我们dep做差就能逼近答案。   (边--对应了区间划分)

dep做差的前提是我们选择的参照物一致,都是树根,但并非询问的L或者R,会导致答案可能多1,所以我们应该靠齐参照物L,那么我们还要找到L对应到dep[R]的那一层的祖先(这里保存了每一层的节点,利用dfs序找),看它的位置是否包括了R,不包括的话,答案-1。

(由于K的存在,实际操作的是一个森林。

(道理就是一个尺子,量长度,向下取整。 如果我以[0,1]作为起点,答案可能+1,可能是正确的,逼近了这个答案后去验证。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=1e6+;
int a[maxn],dep[maxn],dfn[maxn],To[maxn];
int pre[maxn],tot; ll sum[maxn];
vector<int>G[maxn],C[maxn]; //G保存树,C保存每一层。
void dfs(int u,int f){
dep[u]=dep[f]+; dfn[u]=++tot; To[tot]=u;
C[dep[u]].push_back(tot);
for(int i=;i<G[u].size();i++) dfs(G[u][i],u);
}
int Ac(){
int N,Q,K,L,R;
scanf("%d%d%d",&N,&Q,&K);
rep(i,,N) scanf("%d",&a[i]); a[N+]=K+;
rep(i,,N+) pre[i]=pre[i-]+(a[i]>K), sum[i]=sum[i-]+a[i];
int now=N+;
for(int i=N;i>=;i--){
if(a[i]>K) { now=i; continue;}
int pos=upper_bound(sum+,sum+N+,sum[i-]+K)-sum;
pos=min(pos,now); G[pos].push_back(i);
}
for(int i=N+;i>=;i--) if(a[i]>K) dfs(i,i+);
while(Q--){
scanf("%d%d", &L, &R);
if(pre[R]-pre[L-]!=){
puts("Chtholly");
continue;
}
int res=dep[L]-dep[R]+;
int pos=upper_bound(C[dep[R]].begin(),C[dep[R]].end(),dfn[L])-C[dep[R]].begin();
if(To[C[dep[R]][pos-]]>R) res--;
printf("%d\n",res);
}
return ;
}
int main(){
Ac();
return ;
}

牛客82-B:区间的连续段 (ST表,贪心)(WXK牛逼)的更多相关文章

  1. 牛客练习赛14B 区间的连续段

    题目链接 点我跳转 题目大意 给定一个长度为 \(N\) 的序列 \(A\) 和一个常数 \(K\) 有 \(M\) 次询问 每次询问查询一个区间 \([L , R]\) 内所有数最少分成多少个连续段 ...

  2. 区间的连续段~ST表(模板题)

    链接:https://www.nowcoder.com/acm/contest/82/B来源:牛客网 时间限制:C/C++ 7秒,其他语言14秒 空间限制:C/C++ 262144K,其他语言5242 ...

  3. 牛客练习赛14 B 区间的连续段 (倍增)

    链接:https://ac.nowcoder.com/acm/contest/82/B来源:牛客网 区间的连续段 时间限制:C/C++ 7秒,其他语言14秒 空间限制:C/C++ 262144K,其他 ...

  4. HDU1556 Color the ball & 牛客 contest 135-I 区间 [差分标记]

    一.差分标记介绍 差分标记用来解决针对区间(修改-查询)的问题,复杂度比线段树要更低.推荐这个博客. 例如,给数组中处于某个区间的数进行加减操作,然后查询某个位置上数的变化值. 二.HDU1556 C ...

  5. P2486 [SDOI2011]染色(树剖)区间覆盖+区间的连续段

    https://www.luogu.org/problemnew/show/P2486 值的一看https://www.cnblogs.com/Tony-Double-Sky/p/9283262.ht ...

  6. 牛客练习赛16 A 字典序最大的子序列【贪心】

    链接:https://www.nowcoder.com/acm/contest/84/A 来源:牛客网 [出处]:http://codeforces.com/contest/196/problem/A ...

  7. hdu 2871 Memory Control (区间合并 连续段的起始位置 点所属段的左右端点)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2871 题意: 四种操作: 1.Reset  清空所有内存2.New x  分配一个大小为x的内存块返回,返 ...

  8. 牛客多校第八场 G Gemstones 栈/贪心

    题意: 对于一个序列,把可以把连着三个相同的字母拿走,问最多拿走多少组. 题解: 直接模拟栈,三个栈顶元素相同则答案+1,并弹出栈 #include<bits/stdc++.h> usin ...

  9. [暴力+前缀和]2019牛客暑期多校训练营(第六场)Upgrading Technology

    链接:https://ac.nowcoder.com/acm/contest/886/J来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...

随机推荐

  1. nodepad++格式化html代码

    如果没有安装插件

  2. 七、spring生命周期之初始化和销毁方法

    一.通过@Bean指定初始化和销毁方法 在以往的xml中,我们是这样配置的 <bean id="exampleInitBean" class="examples.E ...

  3. java笔记4

    private关键字 1.是一个权限修饰符.       2.用于修饰成员       3.被私有化的成员只能在本类中有效 常用之一: -将成员变量私有化,对外提供对应的set,get方法对其进行访问 ...

  4. SQL——WHERE子句

    一.WHERE字句的基本用法 WHERE字句用于筛选数据,提取满足条件的记录. WHERE字句的基本用法: SELECT * from 表名 WHERE 条件语句; 二.WHERE字句与删改查 演示s ...

  5. Linux组管理、用户管理、查看用户信息、usermod、which、切换用户、修改文件具体权限

    组管理 提示:创建组/删除组的终端命令都需要通过sudo执行 序号 命令 作用 01 groupadd组名 添加组 02 groupdel组名 删除组 03 cat/etc/group 确认组信息 0 ...

  6. Django模型层之单表操作

    Django模型层之单表操作 一 .ORM简介 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数据库管理软 ...

  7. docker(四):集群swarm

    docker使用入门(四):集群swarm swarm是一组位于同一集群且运行docker的机器,用户可以通过swarm manager向swarm输入命令,swarm中的机器可以是虚拟机也可以是物理 ...

  8. L2R 三:常用工具包介绍之 XGBoost与LightGBM

    L2R最常用的包就是XGBoost 和LightGBM,xgboost因为其性能及快速处理能力,在机器学习比赛中成为常用的开源工具包, 2016年微软开源了旗下的lightgbm(插句题外话:微软的人 ...

  9. JAVA MyBybatis分页

    java: import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; impo ...

  10. matlab安装与使用

    Matlab安装和使用 百度网盘连接:https://pan.baidu.com/s/1aHPeAkNofCuwyYopnva4Mg 提取码:ci96 下载完成后: 将R2017b_win64_dvd ...