求一个区间的最大连续子序列,基本想法就是分治,这段子序列可能在区间的左半边,也可能在区间的右半边,也有可能是横跨区间中点,这样就是左子区间的最大后缀加上右子区间的最大前缀之和。

线段树维护三个信息:区间最大前缀、最大后缀、最大连续子区间的下标。

最大前缀可以通过递推来求:要么是左子区间的最大前缀和、要么是左子区间的和 加上 右子区间的最大前缀和

最大后缀和的递推类似。

递推之前要预处理整个序列的前缀和。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#define MP make_pair
#define lch(o) (o*2)
#define rch(o) (o*2+1)
using namespace std; typedef long long LL;
typedef pair<int, int> Interval;
const int maxn = + ;
const int maxnode = + ; LL prefix_sum[maxn]; LL sum(int a, int b) { return prefix_sum[b] - prefix_sum[a-]; } LL sum(Interval p) { return sum(p.first, p.second); } Interval better(Interval a, Interval b)
{
if(sum(a) != sum(b)) return sum(a) > sum(b) ? a : b;
return a < b ? a : b; //pair自带字典序
} int qL, qR; //查询区间 struct IntervalTree
{
int max_prefix[maxnode], max_suffix[maxnode];
Interval max_sub[maxnode]; void build(int o, int L, int R)
{
if(L == R) { max_prefix[o] = max_suffix[o] = L; max_sub[o] = MP(L, L); }
else
{
int M = (L + R) >> ;
int lc = lch(o), rc = rch(o);
build(lc, L, M);
build(rc, M+, R); //递推max_prefix
LL v1 = sum(L, max_prefix[lc]);
LL v2 = sum(L, max_prefix[rc]);
if(v1 == v2) max_prefix[o] = min(max_prefix[lc], max_prefix[rc]);
else max_prefix[o] = v1 > v2 ? max_prefix[lc] : max_prefix[rc]; //递推max_suffix
v1 = sum(max_suffix[lc], R);
v2 = sum(max_suffix[rc], R);
if(v1 == v2) max_suffix[o] = min(max_suffix[lc], max_suffix[rc]);
else max_suffix[o] = v1 > v2 ? max_suffix[lc] : max_suffix[rc]; //递推max_sub
max_sub[o] = better(max_sub[lc], max_sub[rc]);
max_sub[o] = better(max_sub[o], MP(max_suffix[lc], max_prefix[rc]));
}
} Interval query_prefix(int o, int L, int R)
{
if(max_prefix[o] <= qR) return MP(L, max_prefix[o]);
int M = (L + R) >> ;
int lc = lch(o), rc = rch(o);
if(qR <= M) return query_prefix(lc, L, M);
Interval i = query_prefix(rc, M+, R);
i.first = L;
return better(i, MP(L, max_prefix[lc]));
} Interval query_suffix(int o, int L, int R)
{
if(max_suffix[o] >= qL) return MP(max_suffix[o], R);
int M = (L + R) >> ;
int lc = lch(o), rc = rch(o);
if(qL > M) return query_suffix(rc, M+, R);
Interval i = query_suffix(lc, L, M);
i.second = R;
return better(i, MP(max_suffix[rc], R));
} Interval query(int o, int L, int R)
{
if(qL <= L && R <= qR) return max_sub[o];
int M = (L + R) >> ;
int lc = lch(o), rc = rch(o);
if(qR <= M) return query(lc, L, M);
if(qL > M) return query(rc, M+, R);
Interval i1 = query_suffix(lc, L, M);//左子区间的最大后缀
Interval i2 = query_prefix(rc, M+, R);//右子区间的最大前缀
Interval i3 = better(query(lc, L, M), query(rc, M+, R));//两个子区间的最大连续和
return better(i3, MP(i1.first, i2.second));
}
}tree; int main()
{
//freopen("in.txt", "r", stdin); int kase = , n, a, Q;
while(scanf("%d%d", &n, &Q) == )
{
prefix_sum[] = ;
for(int i = ; i <= n; i++) { scanf("%d", &a); prefix_sum[i] = prefix_sum[i-] + a; }
tree.build(, , n);
printf("Case %d:\n", ++kase);
while(Q--)
{
int L, R;
scanf("%d%d", &L, &R);
qL = L; qR = R;
Interval ans = tree.query(, , n);
printf("%d %d\n", ans.first, ans.second);
}
} return ;
}

代码君

UVa 1400 (线段树) "Ray, Pass me the dishes!"的更多相关文章

  1. UVA 1400 线段树

    input n m 1<=n,m<=500000 a1 a2 ... an |ai|<=1e9 m行查询 每行一对a b output 对于每对a b输出区间[a,b]中最小连续和x ...

  2. UVA 1400."Ray, Pass me the dishes!" -分治+线段树区间合并(常规操作+维护端点)并输出最优的区间的左右端点-(洛谷 小白逛公园 升级版)

    "Ray, Pass me the dishes!" UVA - 1400 题意就是线段树区间子段最大和,线段树区间合并,但是这道题还要求输出最大和的子段的左右端点.要求字典序最小 ...

  3. UVA 1400 1400 - &quot;Ray, Pass me the dishes!&quot;(线段树)

    UVA 1400 - "Ray, Pass me the dishes!" option=com_onlinejudge&Itemid=8&page=show_pr ...

  4. UvaLA 3938 "Ray, Pass me the dishes!"

                            "Ray, Pass me the dishes!" Time Limit: 3000MS   Memory Limit: Unkn ...

  5. 线段树(区间合并) LA 3989 "Ray, Pass me the dishes!"

    题目传送门 题意:动态最大连续子序列和,静态的题目 分析:nlogn的归并思想.线段树维护结点的三个信息,最大前缀和,最大后缀和,该区间的最大和的两个端点,然后答案是三个的better.书上用pair ...

  6. uva 1400 - "Ray, Pass me the dishes!"

    又是一道线段树区间更新的题: #include<cstdio> #include<algorithm> #include<cstring> #define ll l ...

  7. UVALive 3938 - "Ray, Pass me the dishes!" - [最大连续子列和+线段树]

    题目链接:https://cn.vjudge.net/problem/UVALive-3938 参考刘汝佳书上说的: 题意: 给出一个长度为n的序列, 再给出m个询问, 每个询问是在序列 $[a,b] ...

  8. uva 11525(线段树)

    题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  9. UVA 11297 线段树套线段树(二维线段树)

    题目大意: 就是在二维的空间内进行单个的修改,或者进行整块矩形区域的最大最小值查询 二维线段树树,要注意的是第一维上不是叶子形成的第二维线段树和叶子形成的第二维线段树要  不同的处理方式,非叶子形成的 ...

随机推荐

  1. SQLServer2005:在执行批处理时出现错误。错误消息为: 目录名无效

    删除数据时忘了想delete删除的话会记录日志,更何况是我删除百万条数据,结果还没删完服务器内存就占慢了,一切数据都进不来了,估计这种情况导致我的数据库有问题了,右键打开表提示:目录名无效,执行SQL ...

  2. Window7中Eclipse运行MapReduce程序报错的问题

    按照文档:http://www.micmiu.com/bigdata/hadoop/hadoop2x-eclipse-mapreduce-demo/安装配置好Eclipse后,运行WordCount程 ...

  3. 剑指offer--面试题11

    题目:求数值的整数次方,不考虑大数值情况 即实现函数:double Power(double base, int exponent) 自己所写代码如下: #include "stdafx.h ...

  4. Linux安装python 2.7.9

    1.下载python wget https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tgz 2.解压.编译安装 tar -zxvf Python- ...

  5. jstl表达式使用方法

    1.jstl.jar  servlet.jar支持 2.jsp引入标签库 <%@ taglib prefix="c" uri="http://java.sun.co ...

  6. android C/C++ source files 全局宏定义 .

    \system\core\include\arch\linux-arm AndroidConfig.h * ============================================== ...

  7. NameValueCollection详解

    1.NameValueCollection类集合是基于 NameObjectCollectionBase 类. 但与 NameObjectCollectionBase 不同,该类在一个键下存储多个字符 ...

  8. hdoj 1879 继续畅通工程

    继续畅通工程 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  9. sun.misc.unsafe类的使用

    http://blog.csdn.net/fenglibing/article/details/17138079

  10. jmeter 使用聚合报告分析jtl文件

    对于jmeter测试生成产生的jtl文件除了使用jemter插件来产生csv或者结果,还可以直接用聚合报告来打开,下面来介绍一下怎么操作. 1. 产生jtl文件 注意,默认情况下聚合报告插件只能分析聚 ...