题目

OIVillage 是一个风景秀美的乡村,为了更好的利用当地的旅游资源,吸引游客,推动经济发展,xkszltl 决定修建了一条铁路将当地 $n$ 个最著名的经典连接起来,让游客可以通过火车从铁路起点( $1$ 号景点)出发,依次游览每个景区。为了更好的评价这条铁路,xkszltl 为每一个景区都赋予了一个美观度,而一条旅行路径的价值就是它所经过的景区的美观度之和。不过,随着天气与季节的变化,某些景点的美观度也会发生变化。

xkszltl 希望为每位旅客提供最佳的旅行指导,但是由于游客的时间有限,不一定能游览全部景区,然而他们也不希望旅途过于短暂,所以每个游客都希望能在某一个区间内的车站结束旅程,而 xkszltl 的任务就是为他们选择一个终点使得旅行线路的价值最大。可是当地的景点与前来观光的旅客实在是太多了,xkszltl 无法及时完成任务,于是找到了准备虐杀 NOI2019 的你,希望你能帮助他完成这个艰巨的任务。

【输入格式】

第一行给出一个整数 $n$,接下来一行给出 $n$ 的景区的初始美观度。

第三行给出一个整数 $m$,接下来 $m$ 行每行为一条指令:

$1.~~~0~x~y~k$:表示将 $x$ 到 $y$ 这段铁路边上的景区的美观度加上 $k$;

$2.~~~1~x~y$:表示有一名旅客想要在 $x$ 到 $y$ 这段(含 $x$ 与 $y$ )中的某一站下车,你需要告诉他最大的旅行价值。

【输出格式】

对于每个询问,输出一个整数表示最大的旅行价值。

【样例输入】

5

1 8 -8 3 -7

3

1 1 5

0 1 3 6

1 2 4

【样例输出】

9

22

【数据范围与提示】

对于 $20\%$ 的数据,$n,m≤3000$;

对于 $40\%$ 的数据,$n,m≤30000$;

对于 $50\%$ 的数据,$n,m≤50000$;

另外 $20\%$ 的数据,$n,m≤100000$,修改操作 $≤20$;

对于 $100\%$ 的数据,$n,m≤100000$。

题解

无力吐槽这组超级强(孱弱)的样例(过了样例还是调出了 INF 个错)

题目求得是区间最大前缀和,带区间加值操作

然后发现线段树无法在 $ O(\log n) $ 的时间内维护区间加上一次函数后的最大值

考虑分块维护最大值

记 $ sum(i) $ 表示前缀和,$ num(i) $ 表示块 $ i $ 加上的一次函数,$ d(i) $ 表示这个块需要加上的常数,

那么 $ sum(i)=num(i)\times i +d(i) $

发现最大值形如 $ y=kx+b $,然后就可以在块上维护一个凸包

当块上加一个一次函数时,凸包的点是不会改变的,那么每次加值时就只要每次重构左右两边的两个凸包即可

查询时只要在每一个块的凸包上二分即可

时间:修改时$ O(\sqrt{n}) $,查询时 $ O(\sqrt{n}) $,所以总时间 $ O(m\sqrt{n}\log n) $

代码

 #include<bits/stdc++.h>
#define LL long long
#define db double
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
int R(){
int x;bool f=;char ch;_(!)if(ch=='-')f=;x=ch^;
_()x=(x<<)+(x<<)+(ch^);return f?x:-x;}
const int N=1e5+,M=;
int n,m,a[N],Sz,Mx,p[N],sz[M],tb[M][M];
LL w[N],num[N],f[N],d[N];
db getK(int i,int j){return (db)(w[i]-w[j])/(db)(i-j);}
void update(int x){
int l=(x-)*Sz+,r=min(x*Sz,n),tot=;
p[++tot]=l;
for(int i=l+;i<=r;i++){
while(tot>&&getK(p[tot],p[tot-])<getK(p[tot-],i))
tot--;
p[++tot]=i;
}
sz[x]=tot;
for(int i=;i<=tot;i++)tb[x][i]=p[i];
return;
}
void pushdown(int x){
LL o=num[x];
for(int i=(x-)*Sz+;i<=min(x*Sz,n);i++)
o+=d[x],w[i]+=o;
num[x]=d[x]=;
return;
}
void change(int l,int r,int k){
int x=a[l],y=a[r];LL o=;
pushdown(x);
for(int i=l;i<=min(x*Sz,r);i++)
o+=k,w[i]+=o;
update(x);
for(int i=x+;i<y;i++)
num[i]+=o,d[i]+=k,o+=1ll*Sz*k;
if(x!=y){
pushdown(y);
for(int i=(y-)*Sz+;i<=r;i++)
o+=k,w[i]+=o;
}
o=(r-l+)*k;
for(int i=r+;i<=min(n,y*Sz);i++)w[i]+=o;
update(y);
for(int i=y+;i<=Mx;i++)num[i]+=o;
return;
}
LL find(int i){
if(!i||i>n)return (LL)-2e18;
return (w[i]+num[a[i]]+d[a[i]]*(i-(a[i]-)*Sz));
}
LL work(int x){
int l=,r=sz[x];
while(l<=r){
int mid=(l+r)>>;
LL t1=find(tb[x][mid-]);
LL t2=find(tb[x][mid]);
LL t3=find(tb[x][mid+]);
if (t1<t2 && t2<t3) l=mid+;
else if (t1>t2 && t2>t3) r=mid-;
else return t2;
}
return l;
}
LL query(int l,int r){
int x=a[l],y=a[r];LL ans=-2e18;
for(int i=x+;i<y;i++)
ans=max(ans,work(i));
for(int i=l;i<=min(x*Sz,r);i++)
ans=max(ans,find(i));
if(x!=y)
for(int i=(y-)*Sz+;i<=r;i++)
ans=max(ans,find(i));
return ans;
}
int main(){
n=R(),Sz=sqrt(n);
for(int i=;i<=n;i++)
w[i]=w[i-]+R(),a[i]=(i-)/Sz+;
Mx=a[n],m=R();
for(int i=;i<=Mx;i++)update(i);
for(int i=;i<=m;i++){
int op=R(),x=R(),y=R(),k;
if(op==)printf("%lld\n",query(x,y));
if(!op)k=R(),change(x,y,k);
}
return ;
}

BZOJ2388:旅行规划(travel)——分块凸包的更多相关文章

  1. 2019.01.20 bzoj2388: 旅行规划(分块+凸包)

    传送门 分块好题. 题意:维护区间加,维护区间前缀和的最大值(前缀和指从1开始的). 思路: 考虑分块维护答案. 我们把每个点看成(i,sumi)(i,sum_i)(i,sumi​)答案一定会在凸包上 ...

  2. BZOJ2388: 旅行规划(分块 凸包)

    题意 题目链接 Sol 直接挂队爷的题解了 分块题好难调啊qwq #include<bits/stdc++.h> #define LL long long using namespace ...

  3. BZOJ2388 : 旅行规划

    考虑分块,每块维护两个标记$ts,td$. 那么对于块中一个位置$i$,它的实际值为$i\times td+ts+v_i$. 修改的时候,对于整块,直接打标记,对于零散的暴力修改,然后重构凸壳,时间复 ...

  4. 旅行规划(travel)

    题目描述 OIVillage 是一个风景秀美的乡村,为了更好的利用当地的旅游资源,吸引游客,推动经济发展,xkszltl 决定修建了一条铁路将当地 nnn 个最著名的经典连接起来,让游客可以通过火车从 ...

  5. 「BZOJ2388」旅行规划

    传送门 分块+凸包 求出前缀和数组s 对于l~r加上k,相当于s[l]~s[r]加上一个首项为k,公差为k的等差数列.r~n加上k*(r-l+1). 分块之后对每一块维护两个标记,一个记录它加的等差数 ...

  6. BZOJ 2388: 旅行规划 [分块 凸包 等差数列]

    传送门 题意: 区间加和询问一段区间内整体前缀和的最大值 刚才还在想做完这道题做一道区间加等差数列结果发现这道就是.... 唯一的不同在于前缀和一段区间加上等差数列后,区间后面也要加上一个常数!!! ...

  7. bzoj2388(分块 凸包)

    好像没有什么高级数据结构能够很高效地实现这个东西: 那就上万能的分块,我们用一些数形结合的思想,把下标看成横坐标,前缀和的值看成纵坐标: 给区间内每个数都加k相当于相邻两点的斜率都加上k: 这种东西我 ...

  8. @bzoj - 2388@ 旅行规划

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 请你维护一个序列,支持两种操作: (1)某个区间 [x, y] ...

  9. [CSP-S模拟测试]:旅行计划(分块+DP)

    题目传送门(内部题83) 输入格式 第一行两个整数$n,m$ 接下来$m$行,每行三个整数,$u,v,w$,表示从$u$到$v$有一条权值为$w$的边 接下来一行有一个整数$q$,表示$q$天 接下来 ...

随机推荐

  1. re.sub用法

    re.sub功能是对于一个输入的字符串,利用正则表达式,来实现字符串替换处理的功能返回处理后的字符串 re.sub共有五个参数 三个必选参数pattern,repl,string 两个可选参数coun ...

  2. 《高性能Javascript》 Summary(二)

    第四章.算法和流程控制 Algorithms And Flow Control 原因:代码整体结构是执行速度的决定因素之一.代码量少不一定运行速度快,代码量多不一定运行速度慢.性能损失与组织代码和具体 ...

  3. 安装wampserver 计算机丢失msvcr100.dll

    刚刚重新安装了Windows 7 64位系统,再安装Wampserver 2时却提示系统错误,如下图所示: 在网上下载了MSVCR100.dll放到system32文件夹下依然没有用. 百度搜索了一下 ...

  4. <算法笔记>关于快速排序的算法优化排序(顺便给百度百科纠个错)

    快速排序是排序算法之中的基本中的基本,虽然越来越多的接口函数将快速排序“完美的封装了起来”,比如C++中的qsort或者<algorithm>中的sort(与stable_sort相对应) ...

  5. 算法(Algorithms)第4版 练习 1.3.20

    方法实现: //1.3.20 /** * delete the kth element in a linked list, if it exists. * * @param k the kth ele ...

  6. PYTHON 爬虫笔记六:PyQuery库基础用法

    知识点一:PyQuery库详解及其基本使用 初始化 字符串初始化 html = ''' <div> <ul> <li class="item-0"&g ...

  7. 分享知识-快乐自己:Excel快速导入Oracle 数据库

    需求: oracle 数据库有一个student表,现有一个excel表:student.xlsx,需导入oracle数据库student表中. student表的拥有者是c##MLQ1  密码为:x ...

  8. (转)C语言之原码、反码和补码

    原码.反码和补码 1).数据在内存中存储的时候都是以二进制的形式存储的. int num = 10; 原码.反码.补码都是二进制.只不过是二进制的不同的表现形式. 数据是以补码的二进制存储的. 2). ...

  9. Posix线程编程指南(3)

    这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第三篇将向您讲述线程同步. 一.互斥锁尽管在Posix Thread中同样可以使用IPC的信号 ...

  10. Mac使用记录

    ---恢复内容开始--- brew list //查看brew安装东东 ls //当前目录下内容 brew --cache //查看brew下载目录 /usr/local/Cellar/ //隐藏文件 ...