当前位置: 首页 > news >正文

CF515E Drazil and Park【思维+线段树】

题意

有一只猴子,他生活在一个环形的公园里。有 n n n 棵树围绕着公园。第 i i i棵树和第 i + 1 i+1 i+1棵树之间的距离是 d i d_i di ,而第 n n n棵树和第一棵树之间的距离是 d n d_n dn 。第 i i i棵树的高度是 h i h_i hi

这只猴子每天要进行晨跑。晨跑的步骤如下:

· 他先选择两棵树;

· 然后爬上第一棵树;

· 再从第一棵树上下来,接着围绕着公园跑(有两个可能的方向)到第二棵树,然后爬上第二棵树;

· 最后从第二棵树上下来。

但是有一些小孩会在连续的一些树上玩耍。所以猴子不能经过这些树。

比如现在猴子选择的第 x x x棵和第 y y y棵树,那么该早晨他消耗的能量是 2 ( h x + h y ) + d i s t ( x , y ) 2(hx+hy)+dist(x,y) 2(hx+hy)+dist(x,y) 。由于某一条路径是被小孩子占据的,所以他只能跑另外一条,因此 d i s t ( x , y ) dist(x,y) dist(x,y) 是确定的。

现在给出第i天,孩子们会在第 a i a_i ai 棵树和 b i b_i bi 棵树之间玩耍。具体的,如果 a i ≤ b i ai≤bi aibi ,那么孩子玩耍的区间就是 [ a i , b i ] [ai,bi] [ai,bi] ,否则孩子玩耍的区间就是 [ a i , n ] ⋃ [ 1 , b i ] [ai,n]⋃[1,bi] [ai,n][1,bi]

请帮助这只猴子找出两棵树,让他晨跑的时候他能够消耗最大的能量。

时间限制

2.00s

内存限制

500.00MB

思路

看到环形结构,第一个想法就是断环成链。
之后我们令, s u m i sum_i sumi表示从起点到 i i i的距离,也就是 d d d数组的前缀和,那么 2 ( h x + h y ) + d i s t ( x , y ) = 2 h x + 2 h y + s u m y − s u m x = s u m y + 2 h y − ( s u m x − 2 h x ) 2(hx+hy)+dist(x,y)=2hx+2hy+sum_y-sum_x=sum_y+2hy-(sum_x-2hx) 2(hx+hy)+dist(x,y)=2hx+2hy+sumysumx=sumy+2hy(sumx2hx),那么如果我们可以求出 s u m i + 2 h i sum_i+2hi sumi+2hi的最大值和 s u m i − 2 h i sum_i-2hi sumi2hi的最小值,就可以得到每次询问的答案。
可以使用线段树或者ST表维护这两个最值对应的下标,对于询问 ( l , r ) (l,r) (l,r),如果两个最值的下标相同,为 p p p,那么由于要求两颗不同的树,于是需要在 ( l , p − 1 ) (l, p - 1) (l,p1) ( p + 1 , r ) (p + 1, r) (p+1,r)中再查询一下,具体看代码啦,很简单滴。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <cmath>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 100005;

int d[N * 2], h[N * 2];
LL s1[N * 2], s2[N * 2];

struct Tree
{
    int l, r;
    int mxp, mip;
}t[N << 4];

int calcMx(int i, int j)
{
    return s1[i] > s1[j] ? i : j;
}

int calcMi(int i, int j)
{
    return s2[i] < s2[j] ? i : j;
}

void push_up(int i)
{
    t[i].mip = calcMi(t[i << 1].mip, t[i << 1 | 1].mip);
    t[i].mxp = calcMx(t[i << 1].mxp, t[i << 1 | 1].mxp);
}

void build(int i, int l, int r)
{
    t[i].l = l, t[i].r = r;
    if (l == r)
    {
        t[i].mxp = t[i].mip = l;
        return;
    }
    int mid = (l + r) >> 1;
    build(i << 1, l, mid);
    build(i << 1 | 1, mid + 1, r);
    push_up(i);
}

int queryMi(int i, int l, int r)
{
    if (l <= t[i].l && t[i].r <= r) return t[i].mip;
    int mid = (t[i].l + t[i].r) >> 1;

    if (l > mid) return queryMi(i << 1 | 1, l, r);
    else if(r <= mid) return queryMi(i << 1, l, r);
    else return calcMi(queryMi(i << 1, l, r), queryMi(i << 1 | 1, l, r));
}

int queryMx(int i, int l, int r)
{
    if (l <= t[i].l && t[i].r <= r) return t[i].mxp;
    int mid = (t[i].l + t[i].r) >> 1;

    if (l > mid) return queryMx(i << 1 | 1, l, r);
    else if(r <= mid) return queryMx(i << 1, l, r);
    else return calcMx(queryMx(i << 1, l, r), queryMx(i << 1 | 1, l, r));
}

int getMx(int l, int r)
{
    if (l > r) return 0;
    return queryMx(1, l, r);
}

int getMi(int l, int r)
{
    if (l > r) return 0;
    return queryMi(1, l, r);
}

LL solve(int l, int r)
{
    int mxp = getMx(l, r), mip = getMi(l, r);
    if (mip != mxp) return s1[mxp] - s2[mip];
    int mxpp = calcMx(getMx(l, mxp - 1), getMx(mxp + 1, r));
    int mipp = calcMi(getMi(l, mxp - 1), getMi(mxp + 1, r));
    return max(s1[mxp] - s2[mipp], s1[mxpp] - s2[mip]);
}

int main()
{
    #ifdef ZYCMH
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
    #endif
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ ) scanf("%d", &d[i % n + 1]), d[i % n + 1 + n] = d[i % n + 1];
    for (int i = 1; i <= n; i ++ ) scanf("%d", &h[i]), h[i + n] = h[i];

    LL sum = 0;
    s1[0] = -1e18;
    s2[0] = 1e18;
    for (int i = 1; i <= n * 2; i ++ )
    {
        sum += d[i];
        s1[i] = sum + 2 * h[i];
        s2[i] = sum - 2 * h[i];
    }

    build(1, 1, 2 * n);

    for (int i = 1; i <= m; i ++ )
    {
        int l, r;
        scanf("%d%d", &l, &r);
        if (l <= r) printf("%lld\n", solve(r + 1, l - 1 + n));
        else printf("%lld\n", solve(r + 1, l - 1));
    }

    return 0;
}

相关文章:

  • CodeForces 1717E【线性筛】
  • Java程序猿搬砖笔记(九)
  • ROS1云课→16机器人模型从urdf到xacro
  • 花好月圆│以代码寄相思,绘嫦娥之奔月
  • WiFi基础学习到实战(一)
  • Java 在Word文档中添加艺术字
  • 打印机打印数量和碳粉监视器 2.2--PrintLimit Print Tracking
  • 懒惰型性格分析,如何改变懒惰型性格?
  • 为什么工作不能让人满意?
  • 【WSN定位】基于chan、taylor算法实现移动基站无源定位附matlab代码
  • Object.freeze()详解——只支持浅冻结-冻结对象的直接属性,不支持深冻结-对象的对象不支持冻结 vue中定义常量文件和导入常量文件
  • 一文入魂:再也不用担心我不懂C++移动语义了!
  • js中,函数的两种命名方式-声明式、函数表达式 自执行匿名函数 (function(){})()之删除对象中的属性
  • 数据建模之查文献找数据以及数据预处理
  • 数字藏品有何价值
  • python3.6+scrapy+mysql 爬虫实战
  • 【笔记】你不知道的JS读书笔记——Promise
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • CentOS 7 修改主机名
  • express如何解决request entity too large问题
  • HashMap剖析之内部结构
  • Java 网络编程(2):UDP 的使用
  • Map集合、散列表、红黑树介绍
  • nfs客户端进程变D,延伸linux的lock
  • opencv python Meanshift 和 Camshift
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • 对象管理器(defineProperty)学习笔记
  • 服务器之间,相同帐号,实现免密钥登录
  • 老板让我十分钟上手nx-admin
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 一文看透浏览器架构
  • 做一名精致的JavaScripter 01:JavaScript简介
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • ​configparser --- 配置文件解析器​
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (51单片机)第五章-A/D和D/A工作原理-A/D
  • (C)一些题4
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (六)软件测试分工
  • (学习日记)2024.02.29:UCOSIII第二节
  • (原)Matlab的svmtrain和svmclassify
  • .naturalWidth 和naturalHeight属性,
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .net core 6 集成 elasticsearch 并 使用分词器
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .Net 垃圾回收机制原理(二)
  • .net 流——流的类型体系简单介绍
  • .NET处理HTTP请求
  • .NET构架之我见
  • .NET教程 - 字符串 编码 正则表达式(String Encoding Regular Express)
  • .NET下ASPX编程的几个小问题