怎么题解全是清一色的 dp?可以用笛卡尔树啊(虽然麻烦了很多,但是我热爱)!

题目传送门。

笛卡尔树的介绍

笛卡尔树,是一种二叉搜索树,它满足如下条件:

  • 每个节点的编号满足二叉搜索树的性质。
  • 每个节点的权值满足小根堆或大根堆的性质。

大概是这个样子:

笛卡尔树的建树

请看这里。

笛卡尔树的用途

它可以用来解决区间最值问题,它有一个重要性质:当这个笛卡尔树为小根堆时,\(\min_{i = l}^r a_i = a_{\operatorname{lca}(l,r)}\),当这个笛卡尔树为大根堆时,\(\max_{i = l}^r a_i = a_{\operatorname{lca}(l,r)}\)。

所以,我们要求一个区间的最小值,只需将笛卡尔树建成小根堆的样式,按照性质求,如果要求一个区间的最大值,只需将笛卡尔树建成大根堆的样式,按照性质求。

当然,它还可以求有多少个区间的最小值或最大值为 \(a_i\),只需看有对少对区间的两端点的最近公共祖先是 \(i\) 即可,由于要使 \(\operatorname{lca}(l,r) = i\),那么 \(l\) 肯定在 \(i\) 的左子树或是 \(i\),\(r\) 肯定在 \(i\) 的右子树或是 \(i\),所以,设 \(s_i\) 表示 \(i\) 这个子树的大小,\(l_i\) 表示 \(i\) 的左儿子,\(r_i\) 表示 \(i\) 的右儿子,则就有 \((s_{l_i}+1) \times (s_{r_i}+1)\) 对区间的两端点的最近公共祖先为 \(i\)。

此题做法

设当前位置有树则当前位置为 \(1\),当前位置没有树则当前位置为 \(0\)。

首先使用前缀和将每个位置往上有多少个连续的 \(1\),设这个数组为 \(f\)。

我们枚举每一行的每个位置。

然后放个假设图(其中一行):

图可能有点丑,请谅解(感谢)!!

假设这是第 \(k\) 行的 \(f\) 数组情况,其中第 \(i\) 个柱子的高度是 \(f_{k,i}\) 对于这第 \(k\) 行,如果要使矩阵的高为第二个柱子,那么它必须得找高度比它高或相等的柱子拼起来才行,所以得找到最左边的一个柱子 \(j\),使得 \(j \le i\) 并且从 \(j\) 到 \(i\) 这些柱子的高度都大于等于等于柱子 \(i\) 的高度,那么这个 \(j\) 就是高为第 \(i\) 个柱子的矩形的左端点,然后再找到 \(k\),使得 \(k<i\) 并且从 \(i\) 到 \(k\) 这些柱子的高度都大于等于等于柱子 \(i\) 的高度,那么这个 \(k\) 就是高为第 \(i\) 个柱子的矩形的右端点,到这里大家都知道可以用单调栈做了吧,但是,我们是要用笛卡尔树的,所以还没完。实际上我们就是要找到区间长度最大的 \([j,k]\),使得 \(\min_{q = j}^k a_q = a_i\),那么就变成了上面说的笛卡尔树的用途的变形,由于我们要使 \([j,k]\) 的长度最大并且满足要求,那么 \(j\) 一定是 \(i\) 的左子树中编号最小的数(如果 \(i\) 没有左子树,那 \(j = i\)),\(k\) 一定是 \(i\) 的右子树中编号最大的数(如果 \(i\) 没有右子树,那 \(k = i\)),这样才能使 \([j,k]\) 长度最大且满足条件,知道了 \([j,k]\) 的长度之后,直接拿长度和当前柱子高度取个最小值就行了。然后求一个子树中编号最小的数和编号最大的数只需找到笛卡尔树的根,然后搜索一下,递推即可。

讲的这么详细,放个代码没问题吧:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+5;
int a[N][N];
int q[N];
int f[N][N];
int l[N];
int r[N];
int depmax[N];
int depmin[N];
int num[N];
void dfs(int x)
{
depmax[x] = x;
depmin[x] = x;
if(l[x])
{
dfs(l[x]);
depmin[x] = min(depmin[x],depmin[l[x]]);
depmax[x] = max(depmax[x],depmax[l[x]]);
}
if(r[x])
{
dfs(r[x]);
depmin[x] = min(depmin[x],depmin[r[x]]);
depmax[x] = max(depmax[x],depmax[r[x]]);
}
}
int main()
{
int n,_;
scanf("%d %d",&n,&_);
while(_--)
{
int x,y;
scanf("%d %d",&x,&y);
a[x][y] = 1;
}
for(int i = 1;i<=n;i++)
{
for(int j = 1;j<=n;j++)
{
if(!a[i-1][j]&&!a[i][j])
{
f[i][j] = f[i-1][j]+!a[i][j];
}
else if(!a[i][j])
{
f[i][j] = 1;
}
}
}
int maxx = 0;
for(int i = 1;i<=n;i++)
{
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
int t = 0;
for(int j = 1;j<=n;j++)
{
while(t&&f[i][q[t]]>f[i][j])
{
l[j] = q[t];
t--;
}
if(t)
{
r[q[t]] = j;
}
q[++t] = j;
}
for(int j = 1;j<=n;j++)
{
num[l[j]] = i;
num[r[j]] = i;
}
for(int j = 1;j<=n;j++)
{
if(num[j]!=i)
{
dfs(j);
break;
}
}
for(int j = 1;j<=n;j++)
{
int ll,rr;
if(l[j])
{
ll = min(depmin[l[j]],j);
}
else
{
ll = j;
}
if(r[j])
{
rr = max(depmax[r[j]],j);
}
else
{
rr = j;
}
maxx = max(maxx,min(f[i][j],rr-ll+1));
}
}
printf("%d",maxx);
return 0;
}

洛谷P2701 [USACO5.3] 巨大的牛棚Big Barn 题解的更多相关文章

  1. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn 题解

    P2701 [USACO5.3]巨大的牛棚Big Barn 题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他 ...

  2. 洛谷——P2701 [USACO5.3]巨大的牛棚Big Barn

    P2701 [USACO5.3]巨大的牛棚Big Barn 题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他 ...

  3. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  4. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  5. 洛谷—— P2701 [USACO5.3]巨大的牛棚Big Barn

    https://www.luogu.org/problem/show?pid=2701 题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的 ...

  6. luogu P2701 [USACO5.3]巨大的牛棚Big Barn |动态规划

    题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N x N 的方格.输入数据中包括有树的 ...

  7. P2701 [USACO5.3]巨大的牛棚Big Barn

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  8. 洛谷P1345 [USACO5.4]奶牛的电信Telecowmunication【最小割】分析+题解代码

    洛谷P1345 [USACO5.4]奶牛的电信Telecowmunication[最小割]分析+题解代码 题目描述 农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流. ...

  9. 洛谷P4014 分配问题【最小/大费用流】题解+AC代码

    洛谷P4014 分配问题[最小/大费用流]题解+AC代码 题目描述 有 n 件工作要分配给 n 个人做.第 i 个人做第 j 件工作产生的效益为c ij. 试设计一个将 n 件工作分配给 n 个人做的 ...

  10. 洛谷 [P2701] 巨大的牛棚

    首先,本题是一道最大子矩阵问题,且m,n较小,可以使用DP做, 与 洛谷 [P1387]最大正方形 做法相同. #include <iostream> #include <cstdi ...

随机推荐

  1. thinkphp6.0封装数据库及缓存模型

    项目中的thinkphp6.0\app\common\Model.php 1 <?php 2 /** 3 * 数据库及缓存模型 4 */ 5 namespace app\common; 6 7 ...

  2. Qt音视频开发34-Onvif时间设置

    一.前言 对设备设置时间很有必要,这个是必备的功能,毕竟大部分的前端设备比如摄像机本身不带BIOS电池的,所以没法存储时间,要么设置了NTP地址来同步时间,要么其他设备主动对他进行设置时间,如果时间不 ...

  3. [转]OpenCV三角测量重建triangulatePoints原理解析

    opencv源代码注释 附上opencv三角测量函数的主要代码和注释 cvTriangulatePoints(CvMat* projMatr1, CvMat* projMatr2, CvMat* pr ...

  4. MySql中MySqlParameter的用法

    在C#中,向表person插入一条数据(表person包括两列:id和name),使用MySqlParameter定义表中各列的值. static void Main(string[] args) { ...

  5. java通过apache poi框架读取2007版Excel文件

    java系读写excel文件既可以用jxl库,也可以用POI库,但是,jxl库只支持低版本的excel2003,不支持更高版本,无法直接输出*.xlsx文件,只能输出*.xls文件,另外,更新也不频繁 ...

  6. 网络编程入门从未如此简单(三):什么是IPv6?漫画式图文,一篇即懂!

    本文由小枣君分享,文案:小枣君.漫画:杨洋,来自鲜枣课堂,有少许改动,原文链接见文末. 1.引言 网络编程能力对于即时通讯技术开发者来说是基本功,而计算机网络又是网络编程的理论根基,因而深刻准确地理解 ...

  7. 巧技拾遗 | JavaScript 中 Array.every 和 Array.map 的巧妙结合

    这几天在跟着学一点 vue3 + TypeScript 中表单验证的实例,看到一个实现,觉得非常巧妙. 需求概述 我们有一个列表 funcArr ,里面存放函数,比如 funcArr = [ func ...

  8. Windows 系统下 Docker 和 Docker Compose 安装配置:一键部署有来开源项目本地环境

    作者主页: 有来技术 开源项目: youlai-mall vue3-element-admin youlai-boot vue-uniapp-template 仓库主页: GitCode Gitee ...

  9. Solution -「LOJ #6895」Yet Another NPC Problem

    \(\mathscr{Description}\)   Link.   给定 \(l,m\),求当 \(k=m,m+1,\dots,m+l-1\) 时,所有 \(k\) 阶有标号简单无向图中,最大团大 ...

  10. 基于C#实现多线程启动停止暂停继续

    大家好!我是付工. 大部分初学者在学习C#上位机编程时,多线程是一个很难逾越的鸿沟,不合理地使用多线程,会导致经常出现各种奇怪的问题,这也是很多初学者不敢使用多线程的原因.但是在实际开发中,多线程是一 ...