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

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

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

最大后缀和的递推类似。

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

 #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. Eclipse 项目管理控制软件svn

    ^_^太开心了,之前以为eclipse只有tortoiseSVN而没有类似Visual Studio 2010里面的cvs的版本控制软件,不是我讨厌tortoiseSVN,而是我实在不习惯使用这个软件 ...

  2. execute、executeUpdate、executeQuery三者的区别(及返回值)

    1. ResultSet executeQuery(String sql); 执行SQL查询,并返回ResultSet 对象. 2.int executeUpdate(String sql); 可执行 ...

  3. Leetcode#79 Word Search

    原题地址 依次枚举起始点,DFS+回溯 代码: bool dfs(vector<vector<char> > &board, int r, int c, string ...

  4. 【转载】C++ inline 函数

    (一)inline函数(摘自C++ Primer的第三版) 在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联. inline int min(int first, int ...

  5. prim求MST

    PRIM==>>MST模板 #include <iostream> using namespace std; #define typec int #define V 3 con ...

  6. 在IDEA上用python来连接集群上的hive

    1.在使用Python连接hive之前需要将hive中的文件拷贝到自己创建python项目中 cp -r apache-hive--bin/lib/py  /home/jia/Desktop 2.把h ...

  7. Jedis 操作

    http://www.cnblogs.com/liuling/p/2014-4-19-04.html

  8. 学习selenium需要具备的知识或技术

    因为有QTP和JAVA的基础,selenium学起来会快很多,总结下学习selenium所需要具备的知识或技术 1.selenium进行的自动化测试是基于ui层面的,所以html,css,javasc ...

  9. 日期工具类TimeUnit

    import java.util.concurrent.TimeUnit; 2 3 public class TimeUnitDemo { 4 private TimeUnit timeUnit =T ...

  10. JVM基础学习

    public class TestJVM { // 运行时数据区[方法区.堆.程序计数器.虚拟机栈.本地方法栈] private static int _1M = 1024 * 1024; publi ...