题意

[http://www.ioi2013.org/wp-content/uploads/tasks/day1/wombats/Wombats zh (CHN).pdf](http://www.ioi2013.org/wp-content/uploads/tasks/day1/wombats/Wombats zh (CHN).pdf)

思路

​ 我们设矩形的行数为 \(n(5000)\) ,列数为 \(m(200)\) ,更新次数为 \(U(500)\) ,查询次数为 \(Q(2\times 10^5)\) 。

​ 最暴力的思想是一次更新处理出从一个 \(m^2\) 的数组,代表第一行的每一个点走到最后一行每一个点的最小代价,然后 \({\cal O}(1)\) 回答。处理出这样一个数组的代价是 \({\cal O}(nm^2)\) 的,于是我们得到了一个 \({\cal O}(Unm^2+Q)\) 的做法。

​ 考虑到我们可以直接把上述二维数组看成矩阵,从而 \(\cal O(m^3)\) 的合并两个二维数组,那么在假如没有空间限制,我们就可以在 \(n\) 那一维上套线段树,从而做到 \({\cal O}(nm^3+Um^3\log n+Q)\) 的时间复杂度。

​ 再仔细观察一下题设,我们发现在作矩阵乘法的时候。\(C(i,j)\leftarrow \displaystyle\min_k\{ A(i,k)+B(k,j)\}\) 随着 \(i\) 变大, 最后起更新作用的 \(k\) 变大;随着 \(j\) 变大, 最后起更新作用的 \(k\) 也变大。于是我们发现了决策单调性,一次矩阵乘法的复杂度降到了 \({\cal O}(m^2)\) 。这是本题最关键的结论,现在复杂度被降到了\({\cal O}(nm^2+Um^2\log n+Q)\) 。

​ 这个算法在时间上已经没有问题了,但是空间开不下,于是我们想到了缩减 \(n\) 。不妨先对原序列进行分块,再以块为基本元素维护线段树即可。块内就直接用最开始讲的暴力做法 \({\cal O}(nm^2)\) 的更新(当然你也可以矩乘),线段树的 \(\text{push_up}\) 操作就是 \({\cal O}(m^2)\) 的矩乘。

​ 设块大小是 \(S\) ,最终时间复杂度为 \(\displaystyle {\cal O}{\big(}nm^2+Um^2(S+\log{n\over S})+Q{\big )}\) ,空间复杂度为 \(\displaystyle {\cal O}(nm+{n\over S}m^2)\) 。块大小越小越好,只要不炸空间。

代码

#include<bits/stdc++.h>
#define FOR(i, x, y) for(register int i = (x), i##END = (y); i <= i##END; ++i)
#define DOR(i, x, y) for(register int i = (x), i##END = (y); i >= i##END; --i)
template<typename T, typename _T> inline bool chk_min(T &x, const _T &y) {return y < x ? x = y, 1 : 0;}
template<typename T, typename _T> inline bool chk_max(T &x, const _T &y) {return x < y ? x = y, 1 : 0;}
typedef long long ll;
const int N = 5005;
const int M = 205;
const int S = 7;
int R[N][M], D[N][M];
int dp[(N / S + 5) << 2][M][M];
int ans[M][M]; bool mark;
int n, m, q; inline int bid(int k) {return k / S;}
inline int bl(int k) {return std::max(1, k * S);}
inline int br(int k) {return std::min(n, (k + 1) * S - 1);} void mul(int C[M][M], int A[M][M], int B[M][M])
{
static int s[M][M];
FOR(x, 0, m + 1) FOR(y, 0, m + 1) s[x][y] = -1;
FOR(x, 1, m)
DOR(y, m, 1)
{
C[x][y] = 2e9;
int l = 1, r = m;
if(~s[x - 1][y]) chk_max(l, s[x - 1][y]);
if(~s[x][y + 1]) chk_min(r, s[x][y + 1]);
FOR(z, l, r)
if(chk_min(C[x][y], A[x][z] + B[z][y]))
s[x][y] = z;
}
} void construct(int x, int dp[M][M])
{
int u = bl(x), d = br(x);
FOR(i, 1, m)
{
dp[i][i] = 0;
int sum = 0;
DOR(j, i - 1, 1)
{
sum += R[u][j];
dp[i][j] = sum;
}
sum = 0;
FOR(j, i + 1, m)
{
sum += R[u][j - 1];
dp[i][j] = sum;
}
FOR(j, 1, m) dp[i][j] += D[u][j]; FOR(x, u + 1, d)
{
FOR(j, 2, m) chk_min(dp[i][j], dp[i][j - 1] + R[x][j - 1]);
DOR(j, m - 1, 1) chk_min(dp[i][j], dp[i][j + 1] + R[x][j]);
FOR(j, 1, m) dp[i][j] += D[x][j];
}
}
} void build(int k, int l, int r)
{
if(l == r)
{
construct(l, dp[k]);
return;
}
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
mul(dp[k], dp[k << 1], dp[k << 1 | 1]);
} void update(int k, int x, int l, int r)
{
if(l == r)
{
construct(l, dp[k]);
return;
}
int mid = (l + r) >> 1;
if(x <= mid) update(k << 1, x, l, mid);
else update(k << 1 | 1, x, mid + 1, r);
mul(dp[k], dp[k << 1], dp[k << 1 | 1]);
} int main()
{
scanf("%d%d", &n, &m);
FOR(i, 1, n) FOR(j, 1, m - 1) scanf("%d", &R[i][j]);
FOR(i, 1, n - 1) FOR(j, 1, m) scanf("%d", &D[i][j]); build(1, bid(1), bid(n)); scanf("%d", &q);
while(q--)
{
int cmd, u, v, w;
scanf("%d%d%d", &cmd, &u, &v);
u++, v++;
if(cmd == 1)
{
scanf("%d", &w);
R[u][v] = w;
update(1, bid(u), bid(1), bid(n));
}
else if(cmd == 2)
{
scanf("%d", &w);
D[u][v] = w;
update(1, bid(u), bid(1), bid(n));
}
else if(cmd == 3)
printf("%d\n", dp[1][u][v]);
} return 0;
}

IOI 2013 袋熊(线段树+分块+决策单调性)的更多相关文章

  1. [Noi2016]区间[离散化+线段树维护+决策单调性]

    4653: [Noi2016]区间 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 621  Solved: 329[Submit][Status][D ...

  2. 洛谷 P5897 - [IOI2013]wombats(决策单调性优化 dp+线段树分块)

    题面传送门 首先注意到这次行数与列数不同阶,列数只有 \(200\),而行数高达 \(5000\),因此可以考虑以行为下标建线段树,线段树上每个区间 \([l,r]\) 开一个 \(200\times ...

  3. BZOJ 1798 (线段树||分块)的标记合并

    我原来准备做方差的.. 结果发现不会维护两个标记.. 就是操作变成一个 a*x+b ,每次维护a , b 即可 加的时候a=1 ,b=v 乘的时候a=v ,b=0 #include <cstdi ...

  4. [luogu1198][bzoj1012][JSOI2008]最大数【线段树+分块】

    题目描述 区间查询最大值,结尾插入,强制在线. 分析 线段树可以做,但是练了一下分块,发现自己打错了两个地方,一个是分块的地方把/打成了%,还有是分块的时候标号要-1. 其他也没什么要多讲的. 代码 ...

  5. L3-2 森森快递 (30 分)(贪心+线段树/分块)

    题目链接:https://pintia.cn/problem-sets/1108203702759940096/problems/1108204121661857798 题目大意: 森森开了一家快递公 ...

  6. 计蒜客16492 building(二分线段树/分块)

    题解: 考虑用线段树维护楼的最大值,然后这个问题就很简单了. 每次可以向左二分出比x高的第一个楼a,同理也可以向右二分出另一个楼b,如果a,b都存在,答案就是b-a-1. 注意到二分是可以直接在线段树 ...

  7. CF-558E (线段树/分块)

    解题思路: 很显然突破口就是字符集比较小,分块和线段树都能A 话说线段树时间是分块5倍啊 代码(线段树): #include<cstdio> #include<cstring> ...

  8. bzoj 3585 mex - 线段树 - 分块 - 莫队算法

    Description 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. Input 第一行n,m. 第二行为n个数. 从第三行开始,每行一个询问 ...

  9. 【模拟8.05】优美序列(线段树 分块 ST算法)

    如此显然的线段树,我又瞎了眼了 事实上跟以前的奇袭很像....... 只要满足公式maxn-minn(权值)==r-l即可 所以可以考虑建两颗树,一棵节点维护位置,一棵权值, 每次从一棵树树上查询信息 ...

随机推荐

  1. SqlBulkCopy将DataTable中的数据批量插入数据库中

    #region 使用SqlBulkCopy将DataTable中的数据批量插入数据库中 /// <summary> /// 注意:DataTable中的列需要与数据库表中的列完全一致.// ...

  2. ssh框架被淘汰的原因

    SSH就是Struts2+Spring+Hibernate. 三个组件的简单介绍 Struts2:通俗的讲就是为了完成MVC模型中的C的功能,也就是编写具体的业务逻辑的地方.从他的设计上来看就是请求到 ...

  3. abstract,virtual,override

    1.abstract 可以修饰类和方法,修饰方法时只声明不实现: 2.继承实现abstract类必须通过override实现abstract声明的方法,而virtual方法可选择override(重写 ...

  4. 2.将视图添加到 ASP.NET Core MVC 应用

    在本部分中,将修改 HelloWorldController 类,进而使用 Razor 视图文件来顺利封装为客户端生成 HTML 响应的过程. 当前,Index 方法返回带有在控制器类中硬编码的消息的 ...

  5. linux 环境下部署 Asp.Net Core 项目 访问 oralce 数据库

    1.ASP.NET Core 是一个跨平台的高性能开源框架,可以部署到Linux上,那项目部署在Linux上有哪些好处呢? 1.linux硬件需求小,大部分版本免费,成本低. 2.linux的用户管理 ...

  6. leetcode之求众数

    求众数 给定一个大小为 n 的数组,找到其中的众数. 你可以假设数组是非空的,并且给定的数组总是存在众数. 示例 1: 输入: [3,2,3] 输出: 3 示例 2: 输入: [2,2,1,1,1,2 ...

  7. Spring Cloud Eureka详细说明

    之前学习了如何配置Eureka注册中心.消费者等,关于更详细的一些常用的配置在这里说明. 1.注册中心的自我保护模式 在我们调试Eureka的注册中心时,访问注册中心页面,常常会看见以下提示. 该提示 ...

  8. 【原创】Airflow 简介&如何部署一个健壮的 apache-airflow 调度系统

    声明 本文摘录了很多前辈的文章,原文如下: https://www.jianshu.com/p/2ecef979c606 Airflow 简介 Airflow是一个可编程,调度和监控的工作流平台,基于 ...

  9. [PHP] 项目实践中的自动加载实现

    1.使用spl_autoload_register函数注册一个自己定义的自动加载函数2.当在代码中new一个不存在的类的时候,上面的函数会被调用,不存在的类名会被作为参数传入该函数中3.兼容了两种方式 ...

  10. [基础]斯坦福cs231n课程视频笔记(一) 图片分类之使用线性分类器

    线性分类器的基本模型: f = Wx Loss Function and Optimization 1. LossFunction 衡量在当前的模型(参数矩阵W)的效果好坏 Multiclass SV ...