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$天 接下来 ...
随机推荐
- github 博客模板
http://www.jianshu.com/p/d658ba3b4351 http://jekyllthemes.org/
- Contiki-Timer 概述
Contiki有一个clock模块和一系列timer模块:timer,stimer,ctimer,etimer,和rtimer. 一.clock模块 clock模块提供一些处理系统时间的函数,还有一些 ...
- 父亲节感恩回馈PSD海报
父亲节感恩回馈PSD素材免费下载海报适用于父亲节海报设计 http://www.huiyi8.com/psd/
- python做图笔记
1. 工具选择 了解了基本python,rodeo,anaconda套件这三种工具. (1)基本python,下载安装python的最新版(目前是python3.7).注意要使用安装版.安装好后,一般 ...
- C/C++ 混合编程
[面试] C/C++ 语法(五) -- extern 1. C 调用 C++ 开发的DLL库 C和C++混合编程(__cplusplus 与 external "c" 的使用) # ...
- 1034 Head of a Gang (30)(30 分)
One way that the police finds the head of a gang is to check people's phone calls. If there is a pho ...
- C++正确的cin输入
void test1(void) { int number; cout << ">> pls input a integer number:"; while ...
- dataguard类型转换与模式转化
修改数据保护模式步骤 前提:是否满足转换模式的配置要求 最大保护(Maximum Protection):Standby Database 必须配置Standby Redo Log,Primary D ...
- 浏览器,tab页显示隐藏的事件监听--页面可见性
//监听浏览器tab切换,以便在tab切换之后,页面隐藏的时候,把弹幕停止 document.addEventListener('webkitvisibilitychange', function() ...
- poj1094Sorting It All Out——拓扑排序
题目:http://poj.org/problem?id=1094 看到此题,首先觉得这是一种层层递进的关系,所以可以想到用拓扑排序: 就像人工排序,每次需要找到一个最小的,再找到新的最小的……所以用 ...