怎么题解全是 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\)。

此题做法

首先使用前缀和将每个位置往上有多少个连续的 H,设这个数组为 \(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 = 4e3+5;
char 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];
//计算depmax,depmin
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()
{
while(1)
{
memset(f,0,sizeof(f));
memset(num,0,sizeof(num));
int n,m,k;
scanf("%d %d",&n,&m);
if(!n&&!m)
{
return 0;
}
scanf("%d",&k);
for(int i = 1;i<=n;i++)
{
scanf("%s",a[i]+1);
}
//求前缀和f
for(int i = 1;i<=n;i++)
{
for(int j = 1;j<=m;j++)
{
if(a[i-1][j] == 'H'&&a[i][j] == 'H')
{
f[i][j] = f[i-1][j]+(a[i][j] == 'H');
}
else if(a[i][j] == 'H')
{
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<=m;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<=m;j++)
{
num[l[j]] = i;//记录下这个点有父亲
num[r[j]] = i;//记录下这个点有父亲
}
for(int j = 1;j<=m;j++)
{
if(num[j]!=i)//如果这个点没有父亲
{
dfs(j);
break;
}
}
//计算
for(int j = 1;j<=m;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,(rr-ll+1)*f[i][j]);
}
}
printf("%lld\n",1ll*maxx*k);
}
return 0;
}

题解:SP6517 JOCHEF - Farmer Sepp的更多相关文章

  1. usaco training 4.2.2 The Perfect Stall 最佳牛栏 题解

    The Perfect Stall题解 Hal Burch Farmer John completed his new barn just last week, complete with all t ...

  2. usaco training 4.1.1 麦香牛块 题解

    Beef McNuggets题解 Hubert Chen Farmer Brown's cows are up in arms, having heard that McDonalds is cons ...

  3. POJ 3279(Fliptile)题解

    以防万一,题目原文和链接均附在文末.那么先是题目分析: [一句话题意] 给定长宽的黑白棋棋盘摆满棋子,每次操作可以反转一个位置和其上下左右共五个位置的棋子的颜色,求要使用最少翻转次数将所有棋子反转为黑 ...

  4. usaco training 4.1.3 fence6 题解

    Fence Loops题解 The fences that surround Farmer Brown's collection of pastures have gotten out of cont ...

  5. usaco training 4.1.2 Fence Rails 题解

    Fence Rails题解 Burch, Kolstad, and Schrijvers Farmer John is trying to erect a fence around part of h ...

  6. usaco training 3.4.3 fence9 题解

    Electric Fence题解 Don Piele In this problem, `lattice points' in the plane are points with integer co ...

  7. usaco 2002 月赛 Fiber Communications 题解

    Description Farmer John wants to connect his N (1 <= N <= 1,000) barns (numbered 1..N) with a ...

  8. 洛谷P2891 Dining P1402 酒店之王【类二分图匹配】题解+代码

    洛谷P2891 Dining P1402 酒店之王[类二分图匹配]题解+代码 酒店之王 题目描述 XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的 ...

  9. 题解——洛谷P1550 [USACO08OCT]打井Watering Hole(最小生成树,建图)

    题面 题目背景 John的农场缺水了!!! 题目描述 Farmer John has decided to bring water to his N (1 <= N <= 300) pas ...

  10. Codeforces Round #102 (Div. 1) A. Help Farmer 暴力分解

    A. Help Farmer 题目连接: http://www.codeforces.com/contest/142/problem/A Description Once upon a time in ...

随机推荐

  1. 【Windows】查看笔记本电池寿命/损耗度(查看电池使用时间报告)

    ① Win+r 运行 命令提示符窗口 ② 输入powercfg/batteryreport 你将会得到电池使用时间报告 将这个地址粘贴到浏览器地址栏访问,或者根据这个地址在资源管理器中找到这个文件夹双 ...

  2. 【问题解决】Pycharm、IDAE等乱码问题:运行输出窗口就正常显示,调试乱码的问题

    添加如下内容 -Dfile.encoding=UTF-8 重启软件生效

  3. 2019.12.10笔记——Spring Boot热部署的使用和实现自己的热部署(类加载器相关)

    Spring Boot热部署 热部署的使用 引入依赖 <!-- spring boot热部署的依赖 --> <dependency> <groupId>org.sp ...

  4. Qt音视频开发35-左右通道音量计算和音量不同范围值的转换

    一.前言 视频文件一般会有两个声音通道及左右声道,值有时候一样有时候不一样,很多场景下我们需要对其分开计算不同的音量值,在QAudioFormat中可以获取具体有几个通道,如果是一个通道,则左右通道值 ...

  5. 关于Qt数据库相关开发的一些经验总结

    一.前言 近期花了两个多月时间,将数据库相关的代码重新封装成了各种轮子(这条路必须打通,打通以后,相关项目只需要引入这个组件pri即可),测试了从Qt4.7到Qt6.1的各种版本,测试了odbc.sq ...

  6. Qt编写安防视频监控系统45-图文报表

    一.前言 图文报表对应以前的文字报表,以前的日志查询后,需要打印或者导出,都是一行行的文字记录,近期需要图文警情记录打印和导出,于是彻底趁机将之前的数据导入导出(xls/pdf)及打印组件彻底改造重写 ...

  7. Qt开源作品25-电池电量控件

    一.前言 现在这个时代,智能手机不要太流行,满大街都是,甚至连爷爷奶奶级别的人都会用智能手机,本次要写的控件就是智能手机中的电池电量表示控件,采用纯painter绘制,其实也可以采用贴图,我估计大部分 ...

  8. MIPI/LVDS/PCIE/HDMI 设计规范

      参考链接: 1.MIPI/LVDS/PCIE/HDMI 2.接口简介(HDMI .eDP/DP.LVDS.VGA.YPbPr.DVI.MHL.MIPI-DSI.VbyOneHS) 3.干货 | 带 ...

  9. 基于实践:一套百万消息量小规模IM系统技术要点总结

    本文由公众号"后台技术汇"分享,原题"基于实践,设计一个百万级别的高可用 & 高可靠的 IM 消息系统",原文链接在文末.由于原文存在较多错误和不准确内 ...

  10. C#+ WPF 实现蓝牙转WIFI计步上位机

    前言 一个WIFI上位机,接收底层MPU6050数据,途中转蓝牙从机透传,到蓝牙主机直连WIFI,PC端UDP通信,实现三轴加速度数据传送和计步功能. 项目介绍 本项目基于.NET平台,使用WPF开发 ...