题面传送门

首先注意到这次行数与列数不同阶,列数只有 \(200\),而行数高达 \(5000\),因此可以考虑以行为下标建线段树,线段树上每个区间 \([l,r]\) 开一个 \(200\times 200\) 的数组 \(d_{i,j}\) 表示从 \((l,i)\) 到 \((r,j)\) 的最短路,合并暴力用类似 floyd 的方式进行转移,这样暴力时间复杂度是 \(RC^3+mC^2\log R+q\),空间复杂度 \(RC^2\),其中 \(m\) 为修改次数,一脸无法通过,而且 TL ML 双开花(大雾。

考虑优化这个暴力,由于线段树建树就有个 \(R\),因此这个 \(R\) 是去不掉的,要优化也只能把这个 \(c^3\) 优化掉。注意到一件事情,就是当我们固定上端点(\(i\))时,随着 \(j\) 的增大,\(d_{i,j}\) 的决策点是单调不降的,因为如果出现某个 \(d_{i,j}\) 的决策点 \(p\) 小于 \(d_{i,j+1}\) 的决策点 \(q\),否则 \(i\to j\) 与 \(i\to j+1\) 的最短路径一定有个交点 \(P\),且这个 \(P\) 一定在 \([l,r]\) 中后方(\(>\dfrac{l+r}{2}\)),因此 \(i\to j\) 和 \(i\to j+1\) 这两个最优路径在 \(i\to P\) 的部分不重合,如果这两段长度相等那么我们可以把它们交换一下,答案不变却满足决策点单调性,否则我们完全可以把长度小的一段并到长度大的一段上去,答案更优。对于固定下断点的情况也同理,因此假设 \(p_{i,j}\) 为 \(d_{i,j}\) 的决策点,那么有 \(p_{i-1,j}\le p_{i,j}\le p_{i,j+1}\),决策单调性优化一下可以搞到 \(c^2\)。

这样 TL 倒是 ok 了,可 ML 还是会炸,这里又有一个 trick,我们设一个阈值 \(B\) 当区间长度很小,不超过 \(B\) 时候,直接暴力枚举起点 \(dp\) 求出最短路径即可,这样暴力 DP 复杂度是 \(BC^2\) 的,而我们建树时会 DP \(\dfrac{R}{B}\) 次,每次修改都会 DP 一次,因此空间复杂度是 \(\dfrac{R}{B}C^2\),时间复杂度 \(RC^3+mC^2\log R+q+mBC^2\),刚好卡过去。

据说这东西有个名字叫线段树分块?长见识了(

const int MAXN=5e3;
const int MAXC=200;
const int MAXP=MAXN*4/20;
const int INF=0x3f3f3f3f;
int n,m,hor[MAXN+5][MAXC+5],ver[MAXN+5][MAXC+5];
struct value{
int a[MAXC+5][MAXC+5];
value(){memset(a,63,sizeof(a));}
};
int p[MAXC+5][MAXC+5];
value merge(value a,value b,int vx){
value c;memset(p,0,sizeof(p));
for(int i=1;i<=m;i++) for(int j=m;j;j--){
for(int k=((p[i-1][j])?(p[i-1][j]):1);k<=((p[i][j+1])?p[i][j+1]:m);k++)
if(c.a[i][j]>a.a[i][k]+b.a[k][j]+ver[vx][k])
c.a[i][j]=a.a[i][k]+b.a[k][j]+ver[vx][k],p[i][j]=k;
} return c;
}
struct node{int l,r;value v;} s[MAXP+5];
int dp[MAXN+5][MAXC+5];
value get(int u,int d){
value res;
for(int i=1;i<=m;i++){
for(int j=u;j<=d;j++) for(int k=1;k<=m;k++) dp[j][k]=INF;
dp[u][i]=0;
for(int j=u;j<=d;j++){
if(j!=u) for(int k=1;k<=m;k++) dp[j][k]=dp[j-1][k]+ver[j-1][k];
for(int k=2;k<=m;k++) chkmin(dp[j][k],dp[j][k-1]+hor[j][k-1]);
for(int k=m-1;k;k--) chkmin(dp[j][k],dp[j][k+1]+hor[j][k]);
}
// for(int j=u;j<=d;j++) for(int k=1;k<=m;k++) printf("%d%c",dp[j][k]," \n"[k==m]);
for(int j=1;j<=m;j++) res.a[i][j]=dp[d][j];
} return res;
}
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;if(r-l<=20) return s[k].v=get(l,r),void();
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
s[k].v=merge(s[k<<1].v,s[k<<1|1].v,mid);
}
void modify(int k,int x){
if(s[k].r-s[k].l<=20) return s[k].v=get(s[k].l,s[k].r),void();int mid=s[k].l+s[k].r>>1;
(x<=mid)?modify(k<<1,x):modify(k<<1|1,x);s[k].v=merge(s[k<<1].v,s[k<<1|1].v,mid);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) for(int j=1;j<m;j++) scanf("%d",&hor[i][j]);
for(int i=1;i<n;i++) for(int j=1;j<=m;j++) scanf("%d",&ver[i][j]);
build(1,1,n);int qu;scanf("%d",&qu);
while(qu--){
int opt;scanf("%d",&opt);
if(opt==1){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
++x;++y;hor[x][y]=z;modify(1,x);
} else if(opt==2){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
++x;++y;ver[x][y]=z;modify(1,x);
} else {
int x,y;scanf("%d%d",&x,&y);++x;++y;
printf("%d\n",s[1].v.a[x][y]);
}
}
return 0;
}

洛谷 P5897 - [IOI2013]wombats(决策单调性优化 dp+线段树分块)的更多相关文章

  1. luogu P5892 [IOI2014]holiday 假期 决策单调性优化dp 主席树

    LINK:holiday 考虑第一个subtask. 容易想到n^2暴力枚举之后再暴力计算答案. 第二个subtask 暴力枚举终点可以利用主席树快速统计答案. 第三个subtask 暴力枚举两端利用 ...

  2. 【洛谷5298】[PKUWC2018] Minimax(树形DP+线段树合并)

    点此看题面 大致题意: 有一棵树,给出每个叶节点的点权(互不相同),非叶节点\(x\)至多有两个子节点,且其点权有\(p_x\)的概率是子节点点权较大值,有\(1-p_x\)的概率是子节点点权较小值. ...

  3. Lightning Conductor 洛谷P3515 决策单调性优化DP

    遇见的第一道决策单调性优化DP,虽然看了题解,但是新技能√,很开森. 先%FlashHu大佬,反正我是看了他的题解和精美的配图才明白的,%%%巨佬. 废话不多说,看题: 题目大意 已知一个长度为n的序 ...

  4. CF868F Yet Another Minimization Problem 分治决策单调性优化DP

    题意: 给定一个序列,你要将其分为k段,总的代价为每段的权值之和,求最小代价. 定义一段序列的权值为$\sum_{i = 1}^{n}{\binom{cnt_{i}}{2}}$,其中$cnt_{i}$ ...

  5. 2018.09.28 bzoj1563: [NOI2009]诗人小G(决策单调性优化dp)

    传送门 决策单调性优化dp板子题. 感觉队列的写法比栈好写. 所谓决策单调性优化就是每次状态转移的决策都是在向前单调递增的. 所以我们用一个记录三元组(l,r,id)(l,r,id)(l,r,id)的 ...

  6. [BZOJ4850][JSOI2016]灯塔(分块/决策单调性优化DP)

    第一种方法是决策单调性优化DP. 决策单调性是指,设i>j,若在某个位置x(x>i)上,决策i比决策j优,那么在x以后的位置上i都一定比j优. 根号函数是一个典型的具有决策单调性的函数,由 ...

  7. BZOJ2216 Poi2011 Lightning Conductor 【决策单调性优化DP】

    Description 已知一个长度为n的序列a1,a2,...,an. 对于每个1<=i<=n,找到最小的非负整数p满足 对于任意的j, aj < = ai + p - sqrt( ...

  8. 决策单调性优化dp 专题练习

    决策单调性优化dp 专题练习 优化方法总结 一.斜率优化 对于形如 \(dp[i]=dp[j]+(i-j)*(i-j)\)类型的转移方程,维护一个上凸包或者下凸包,找到切点快速求解 技法: 1.单调队 ...

  9. 算法学习——决策单调性优化DP

    update in 2019.1.21 优化了一下文中年代久远的代码 的格式…… 什么是决策单调性? 在满足决策单调性的情况下,通常决策点会形如1111112222224444445555588888 ...

随机推荐

  1. Golang通脉之类型定义

    自定义类型 在Go语言中有一些基本的数据类型,如string.整型.浮点型.布尔等数据类型, Go语言中可以使用type关键字来定义自定义类型. type是Go语法里的重要而且常用的关键字,type绝 ...

  2. VMware虚拟机安装Linux

    我们都知道,Linux的学习如果依靠大量的物理真机,是不切实际的,会非常的麻烦. 今天来和分享一下VMware虚拟机安装Linux操作系统的方法 (centos  7) 1. 我们要先把VMware虚 ...

  3. 剑指offer:JZ9 用两个栈实现队列

    JZ9 用两个栈实现队列 描述 用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能. 队列中的元素为int类型.保证操作合法,即保 ...

  4. [no code][scrum meeting] Alpha 6

    项目 内容 会议时间 2020-04-13 会议主题 后端技术细节分析 会议时长 30min 参会人员 PM+后端组成员 $( "#cnblogs_post_body" ).cat ...

  5. 使用vuex简单的实现系统中的状态管理

    最近项目中用到了vue,其中状态的集中管理使用到了vuex,因此就学习vuex做一个简单的记录.vuex的官方网址如下: https://vuex.vuejs.org/zh-cn/  vuex 当我们 ...

  6. 表单编辑时el-form的validate方法执行无效,阻塞代码运行 - Element UI踩坑记录

    今天在用element-ui写管理后台需求时,遇到一个奇怪的问题 一个正常带校验的表单,在新增列表数据时表单校验功能正常: 但是在新增之后再去编辑数据时,表单校验却失效了,甚至阻塞了后续的代码执行,控 ...

  7. poj 2060 Taxi Cab Scheme(DAG图的最小路径覆盖)

    题意: 出租车公司有M个订单. 订单格式:     hh:mm  a  b  c  d 含义:在hh:mm这个时刻客人将从(a,b)这个位置出发,他(她)要去(c,d)这个位置. 规定1:从(a,b) ...

  8. 【数据结构&算法】02-复杂度分析之执行效率和资源消耗

    目录 前言 复杂度 分析方法 大 O 复杂度表示法 例子-评估累加和的各种算法执行效率 算法 1(for 循环): 算法 2(嵌套 for 循环): 大 O 表示 时间复杂度分析 关注执行最多的一段代 ...

  9. 新手使用python以及pycharm看过来

    前言 随着互联网时代的进步,人类与计算机之前的沟通交流越来越便捷,自此交流的媒介--编程语言吸引力更多的人学习,今天我们就来谈谈当前市面上最火的编程语言 1.文件的概念 什么是文件夹.文件 其实是操作 ...

  10. CentOS8安装VNC-Server,并使用VNC Viewer连接

    1.查看系统信息 # 查看red-hat版本信息 cat /etc/redhat-release CentOS Linux release 8.0.1905 (Core) 2.安装VNC Server ...