BZOJ2388:旅行规划(travel)——分块凸包
题目
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)——分块凸包的更多相关文章
- 2019.01.20 bzoj2388: 旅行规划(分块+凸包)
传送门 分块好题. 题意:维护区间加,维护区间前缀和的最大值(前缀和指从1开始的). 思路: 考虑分块维护答案. 我们把每个点看成(i,sumi)(i,sum_i)(i,sumi)答案一定会在凸包上 ...
- BZOJ2388: 旅行规划(分块 凸包)
题意 题目链接 Sol 直接挂队爷的题解了 分块题好难调啊qwq #include<bits/stdc++.h> #define LL long long using namespace ...
- BZOJ2388 : 旅行规划
考虑分块,每块维护两个标记$ts,td$. 那么对于块中一个位置$i$,它的实际值为$i\times td+ts+v_i$. 修改的时候,对于整块,直接打标记,对于零散的暴力修改,然后重构凸壳,时间复 ...
- 旅行规划(travel)
题目描述 OIVillage 是一个风景秀美的乡村,为了更好的利用当地的旅游资源,吸引游客,推动经济发展,xkszltl 决定修建了一条铁路将当地 nnn 个最著名的经典连接起来,让游客可以通过火车从 ...
- 「BZOJ2388」旅行规划
传送门 分块+凸包 求出前缀和数组s 对于l~r加上k,相当于s[l]~s[r]加上一个首项为k,公差为k的等差数列.r~n加上k*(r-l+1). 分块之后对每一块维护两个标记,一个记录它加的等差数 ...
- BZOJ 2388: 旅行规划 [分块 凸包 等差数列]
传送门 题意: 区间加和询问一段区间内整体前缀和的最大值 刚才还在想做完这道题做一道区间加等差数列结果发现这道就是.... 唯一的不同在于前缀和一段区间加上等差数列后,区间后面也要加上一个常数!!! ...
- bzoj2388(分块 凸包)
好像没有什么高级数据结构能够很高效地实现这个东西: 那就上万能的分块,我们用一些数形结合的思想,把下标看成横坐标,前缀和的值看成纵坐标: 给区间内每个数都加k相当于相邻两点的斜率都加上k: 这种东西我 ...
- @bzoj - 2388@ 旅行规划
目录 @description@ @solution@ @accepted code@ @details@ @description@ 请你维护一个序列,支持两种操作: (1)某个区间 [x, y] ...
- [CSP-S模拟测试]:旅行计划(分块+DP)
题目传送门(内部题83) 输入格式 第一行两个整数$n,m$ 接下来$m$行,每行三个整数,$u,v,w$,表示从$u$到$v$有一条权值为$w$的边 接下来一行有一个整数$q$,表示$q$天 接下来 ...
随机推荐
- 友盟分享到微信的几点备忘(IOS)
1.下载最新的友盟分享版本,参考友盟官方的demo 2.注册微信开放平台用户,不是公众平台,注册应用 3.参考文档和demo,加入sdk包和相应的lib 4.在plist加入URL types.URL ...
- centos下安装nodejs及websocket
软件环境: VMware Workstation CentOS 6.5 NodeJS v0.12.5 安装过程: Step 1.确认服务器有nodejs编译及依赖相关软件,如果没有可通过运行以下命令安 ...
- redis简介及安装
1 redis简介及安装 1.1 Redis是什么 REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统. 首 ...
- 图解HTTP接口自动化测试框架使用
Robot Framework是一款python语言编写,通用的功能自动化测试框架.它使用了比较易用的表格数据语法,基于关键字驱动测试,主要用来验收测试和验收测试驱动开发(ATDD). 运行RIDE, ...
- linux网络编程 inet_aton(); inet_aton; inet_addr;
. inet_aton()是一个改进的方法来将一个字符串IP地址转换为一个32位的网络序列IP地址. . inet_ntoa() 本函数将一个用in参数所表示的Internet地址结构转换成以“.” ...
- Unity-2017.3官方实例教程Space-Shooter(二)
由于初学Unity,写下此文作为笔记,文中难免会有疏漏,不当之处还望指正. Unity-2017.3官方实例教程Space-Shooter(一) 章节列表: 一.创建小行星Prefab 二.创建敌机和 ...
- 消息队列:快速上手ActiveMQ消息队列的JMS方式使用(两种模式:Topic和Queue的消息推送和订阅)
1.实现功能 希望使用一套API,实现两种模式下的消息发送和接收功能,方便业务程序调用 1.发送Topic 2.发送Queue 3.接收Topic 4.接收Queue 2.接口设计 根据功能设计公共调 ...
- Python3解leetcode Maximum SubarrayClimbing Stairs
问题: You are climbing a stair case. It takes n steps to reach to the top. Each time you can either cl ...
- 【转】STL中的set容器的一点总结
转自 http://www.cnblogs.com/BeyondAnyTime/archive/2012/08/13/2636375.html 1.关于set C++ STL 之所以得到广泛的赞誉,也 ...
- Pokemon Master
Pokemon Master Time Limit : 4000/2000ms (Java/Other) Memory Limit : 131072/65536K (Java/Other) Total ...