http://acm.hdu.edu.cn/showproblem.php?pid=5696

这是这次百度之星初赛2B的第一题,但是由于正好打省赛,于是便错过了。加上2A的时候差了一题,当时有思路,但是代码就是过不去。。这次应该是无缘复赛了。。

先不水了,省赛回来,我看了一下这个题,当时有个类似于快排的想法,今天试了一下,勉强AC了。。跑了3S多。

思路就是我枚举区间左值lt,那么[lt, n]区间内最值的角标分别为mi和ma。于是设to = max(mi, ma)。也就是说在to右侧的所有区间[lt, i]的值至少都是a[mi]*a[ma]。用线段树维护长度为i区间的最值,那么我需要用a[mi]*a[ma]去更新区间[to-lt+1, rt-lt+1]在线段树中的值。然后区间就可以缩减为[lt, to-1]了,于是递归求解就可以了,当然此处可以迭代。

关键是上述的递归过程最多需要运行多少次?

首先to这个位置,要么是mi,要么是ma,也就是说左侧的数据要么都比to这个位置的数小,要么都比它大。光看左侧,这个to很像快排一次运行的那个分隔值。那么to平均下来应该是(lt+rt)/2。

那么总的复杂度就是nlognlogn.

但是此处线段树常数较大,所以需要减一下枝,就是当更新值pls比子树中任意值都小,就可以不用更新,维护子树的最小值就可以了。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>
#define LL long long using namespace std; const int maxN = ;
int n, a[maxN]; //RMQ-ST算法
//效率nlogn
//查询区间最值,注意区间[0, n-1]和[1, n]的区别
int ma[maxN][], mi[maxN][]; void RMQ()
{
memset(ma, , sizeof(ma));
memset(mi, , sizeof(mi));
for (int i = ; i <= n; ++i)
mi[i][] = ma[i][] = i;
for (int j = ; (<<j) <= n; ++j)
for (int i = ; i+(<<j)- <= n; ++i)
{
if (a[ma[i][j-]] >= a[ma[i+(<<(j-))][j-]])
ma[i][j] = ma[i][j-];
else
ma[i][j] = ma[i+(<<(j-))][j-];
if (a[mi[i][j-]] <= a[mi[i+(<<(j-))][j-]])
mi[i][j] = mi[i][j-];
else
mi[i][j] = mi[i+(<<(j-))][j-];
}
} int queryMax(int lt, int rt)
{
int k = ;
while ((<<(k+)) <= rt-lt+)
k++;
if (a[ma[lt][k]] >= a[ma[rt-(<<k)+][k]])
return ma[lt][k];
else
return ma[rt-(<<k)+][k];
} int queryMin(int lt, int rt)
{
int k = ;
while ((<<(k+)) <= rt-lt+)
k++;
if (a[mi[lt][k]] <= a[mi[rt-(<<k)+][k]])
return mi[lt][k];
else
return mi[rt-(<<k)+][k];
} //线段树
//求区间最值
struct node
{
int lt, rt;
LL val, delta;
}tree[*maxN]; //向下更新
void pushDown(int id)
{
if (tree[id].delta != )
{
tree[id<<].val = tree[id<<].delta = max(tree[id<<].val, tree[id].delta);
tree[id<<|].val = tree[id<<|].delta = max(tree[id<<|].val, tree[id].delta);
tree[id].delta = ;
}
} //向上更新
void pushUp(int id)
{
tree[id].val = min(tree[id<<].val, tree[id<<|].val);
} //建立线段树
void build(int lt, int rt, int id)
{
tree[id].lt = lt;
tree[id].rt = rt;
tree[id].val = ;//每段的初值,根据题目要求
tree[id].delta = ;
if (lt == rt)
{
//tree[id].delta = ??;
return;
}
int mid = (lt+rt)>>;
build(lt, mid, id<<);
build(mid+, rt, id<<|);
} //增加区间内每个点固定的值
void change(int lt, int rt, int id, LL pls)
{
if (pls <= tree[id].val) return;
if (lt <= tree[id].lt && rt >= tree[id].rt)
{
tree[id].val = tree[id].delta = max(tree[id].delta, pls);
return;
}
pushDown(id);
int mid = (tree[id].lt+tree[id].rt)>>;
if (lt <= mid)
change(lt, rt, id<<, pls);
if (rt > mid)
change(lt, rt, id<<|, pls);
pushUp(id);
} //查询某段区间内的最值
LL query(int lt, int rt, int id)
{
if (lt <= tree[id].lt && rt >= tree[id].rt)
return tree[id].val;
pushDown(id);
int mid = (tree[id].lt+tree[id].rt)>>;
if (rt <= mid)
return query(lt, rt, id<<);
if (lt > mid)
return query(lt, rt, id<<|);
return max(query(lt, mid, id<<), query(mid+, rt, id<<|));
} void input()
{
for (int i = ; i <= n; ++i) scanf("%d", &a[i]);
RMQ();
build(, n, );
} int cnt; void cal(int lt, int rt)
{
int to, mi, ma;
while (lt <= rt)
{
mi = queryMin(lt, rt);
ma = queryMax(lt, rt);
to = max(mi, ma);
change(to-lt+, rt-lt+, , (LL)a[mi]*a[ma]);
rt = to-;
}
} void work()
{
cnt = ;
for (int i = ; i <= n; ++i)
cal(i, n);
for (int i = ; i <= n; ++i)
printf("%lld\n", query(i, i, ));
} int main()
{
//freopen("test.out", "w", stdout);
//freopen("test.in", "r", stdin);
while (scanf("%d", &n) != EOF)
{
input();
work();
}
return ;
}

ACM学习历程—HDU5696 区间的价值(分治 && RMQ && 线段树 && 动态规划)的更多相关文章

  1. ACM学习历程—Codeforces 446C DZY Loves Fibonacci Numbers(线段树 && 数论)

    Description In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence ...

  2. ACM学习历程——HDU2227 Find the nondecreasing subsequences(线段树 && dp)

    Description How many nondecreasing subsequences can you find in the sequence S = {s1, s2, s3, ...., ...

  3. ACM学习历程——POJ3321 Apple Tree(搜索,线段树)

          Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will ...

  4. ACM学习历程—HDU5700 区间交(树状数组 && 前缀和 && 排序)

    http://acm.hdu.edu.cn/showproblem.php?pid=5700 这是这次百度之星初赛2B的第五题.省赛回来看了一下,有这样一个思路:对于所有的区间排序,按左值排序. 然后 ...

  5. ACM学习历程—HDU5592 ZYB's Premutation(逆序数 && 树状数组 && 二分)(BestCoder Round #65 1003)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5592 题目大意就是给了每个[1, i]区间逆序对的个数,要求复原原序列. 比赛的时候2B了一发. 首先 ...

  6. ACM学习历程—HDU 5536 Chip Factory(xor && 字典树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5536 题目大意是给了一个序列,求(si+sj)^sk的最大值. 首先n有1000,暴力理论上是不行的. ...

  7. ACM学习历程—HDU 5443 The Water Problem(RMQ)(2015长春网赛1007题)

    Problem Description In Land waterless, water is a very limited resource. People always fight for the ...

  8. ACM学习历程——UVA11234 Expressions(栈,队列,树的遍历,后序遍历,bfs)

    Description   Problem E: Expressions2007/2008 ACM International Collegiate Programming Contest Unive ...

  9. ACM学习历程—HDU 5317 RGCDQ (数论)

    Problem Description Mr. Hdu is interested in Greatest Common Divisor (GCD). He wants to find more an ...

随机推荐

  1. selection createTextRange setSelectionRange

    http://www.cnblogs.com/rainman/archive/2011/02/27/1966482.html http://www.zhangxinxu.com/wordpress/2 ...

  2. Django-虚拟环境设置

    Django 虚拟环境virtualenv virtualenv是用来处理多个用python语言进行开发的项目,在同一台机器上部署,不同项目依赖不同第三方库版本所造成的问题. 打个比方,现在你机器上要 ...

  3. VMware 连接不上XSHELL

    本人创建虚拟机时把网络连接模式选成了桥接,后来在VMware虚拟网络编辑器中查看了连接模式:NAT. 重新回到VMware中更改了连接模式:NAT模式 成功连接XSHELL 步骤1 打开VMware的 ...

  4. INSPIRED启示录 读书笔记 - 第40章 最佳实践经验

    十大要点 1.产品管理的职责:许多产品经理将大把的时间浪费在与产品管理无关的工作上 2.用户体验:对于大多数软件产品来说,用户体验就是产品的生命 3.机会评估:用方便快捷的机会评估方法取代过时的市场需 ...

  5. Centos6.5安装glusterfs3.6.2

    硬件环境Centos6.5  glusterfs3.6.2 先安装必要的包 yum install flex bison 2. 下载glusterfs3.6.2 wget http://downloa ...

  6. how to use composer in fiddler

    https://www.cnblogs.com/youxin/p/3570310.html http://docs.telerik.com/fiddler/generate-traffic/tasks ...

  7. 直播P2P技术3-伙伴节点质量评估及子流订阅

    以上模型,暂且称之为W-P2P吧.

  8. QT中phonon的安装和使用

    http://write.blog.csdn.net/postedit Phonon严格来说其实非为Qt的library,Phonon原本就是KDE 4的开放原始码多媒体API,後来与Qt合并与开发, ...

  9. python matrix/array反向切片

    >>> import numpy as np >>> m = np.mat([[1.,1,1],[1,2,3,],[1,5,1,]]) >>> m ...

  10. js字符串转dom

    function parse2dom(str){ var div = document.createElement("div"); if(typeof str == "s ...