博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 1506 单调栈,笛卡尔树,DP
阅读量:3950 次
发布时间:2019-05-24

本文共 2879 字,大约阅读时间需要 9 分钟。

题目

在这里插入图片描述

如图,求最大的矩形面积。

单调栈

维护一个单调递增的栈。当新进来的数小于前面的,前面的高出部分已经起不到作用了。故在加入新的前,弹出所有高出的元素,统计答案。再加入新的值,把宽度设成刚刚弹出的宽度加1。 O ( n ) O(n) O(n)

#include 
#define debug(__x) cout<<#__x<<"="<<__x<
;const int maxn = 1e5+5;int main(){
int T; cin.tie(0),cout.tie(0); ios::sync_with_stdio(false); int n; while(cin>>n && n){
stack
s; s.push(make_pair(0,-1ll)); ll h; ll ans=0; for(int i=1;i<=n+1;++i){
if(i==n+1) h=0; else cin>>h; if(s.top().second
=h){
pii last = s.top(); s.pop(); w += last.first; ans = max(ans, w*last.second); } if(h)s.push(make_pair(w+1,h)); } } cout<
<

笛卡尔树

很明显了,利用笛卡尔树中序遍历为原序列以及父节点权值小于左右儿子的特点。对笛卡尔树每个节点统计一次答案即可。建树过程由于每个节点都最多加入和弹出一次,所以仍然为 O ( n ) O(n) O(n)

#include 
#define debug(__x,_ge) cout<<#__x<<"="<<__x<<_ge#define endl '\n'using namespace std;using ll = long long;using pii = pair
;const int maxn = 1e5+5;struct Node{
int idx, val, par, ch[2];}tree[maxn];int n,top;int stk[maxn];ll ans;void add(int idx){
int k=top; while(k && tree[stk[k]].val > tree[idx].val) --k; if(k!=top){
// 不是右链最后一个 tree[idx].ch[0]=stk[k+1]; tree[stk[k+1]].par = idx; } if(k)tree[stk[k]].ch[1] = idx, tree[idx].par = stk[k]; stk[++k] = idx; top = k;}int dfs(int u){
if(!u)return 0; int siz = dfs(tree[u].ch[0]) + dfs(tree[u].ch[1]) + 1; ans = max(ans, ll(siz) * tree[u].val); return siz;}int main(){
int T; cin.tie(0),cout.tie(0); ios::sync_with_stdio(false); while(cin>>n && n){
top = 0; ans = 0; for(int i=1;i<=n;++i){
cin>>tree[i].val; tree[i].idx = i; tree[i].par = tree[i].ch[0] = tree[i].ch[1] = 0; add(i); } dfs(stk[1]); cout<
<

线性DP

这是来源于最朴树的思想——枚举每个点为矩形高,左右延申最远的距离为矩形宽。左右延展用到了俩个DP数组。

#include 
#define debug(__x,_ge) cout<<#__x<<"="<<__x<<_ge#define endl '\n'using namespace std;using ll = long long;const int maxn = 1e5+5;int L[maxn],R[maxn];ll a[maxn];int main(){
int n; cin.tie(0),cout.tie(0); ios::sync_with_stdio(false); while(cin>>n && n){
for(int i=1;i<=n;++i){
cin>>a[i]; } for(int k,i=1;i<=n;++i){
k = i; while(k!=1 && a[k-1] >= a[i]) k = L[k-1]; L[i] = k; } for(int k,i=n;i>0;--i){
k = i; while(k!=n && a[k+1] >= a[i]) k = R[k+1]; R[i] = k; } ll ans = 0; for(int i=1;i<=n;++i) ans = max(ans, a[i]*(R[i]-L[i]+1)); cout<
<

转载地址:http://mgkzi.baihongyu.com/

你可能感兴趣的文章
android电源管理
查看>>
Android电源管理相关应用技巧分享
查看>>
Linux关机重启流程分析
查看>>
MOS管及MOS管的驱动电路设计
查看>>
ARM中的程序状态寄存器(CPSR)
查看>>
关于c语言的sizeof
查看>>
2440init.s文件分析
查看>>
ADS ARM Assembler内置变量
查看>>
linux设备模型中ktype的用法
查看>>
Linux内核Ramdisk(initrd)机制
查看>>
Linux2.6 内核的 Initrd 机制解析
查看>>
解析linux根文件系统的挂载过程
查看>>
Linux的cpufreq(动态变频)技术
查看>>
Android系统的移植要做的两个工作
查看>>
内核调试案例(oops错误)
查看>>
Linux内核调试 - 一般人儿我都不告诉他(一)
查看>>
Linux内核的Oops
查看>>
基于Linux-2.6.28的 EELiod平台UART驱动分析(一)
查看>>
Linux flash文件系统剖析
查看>>
linux的文件属性和权限学习——分析ls命令结果
查看>>