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

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

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

最大后缀和的递推类似。

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

 #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. windows 2012 服务器打开ping端口,开通远程连接

    windows 2012 服务器打开ping端口,开通远程桌面连接 控制面板->系统与安全->高级防火墙->入站规则 找到:windows 远程桌面 (http in )  右键启用 ...

  2. 2875: [Noi2012]随机数生成器 - BZOJ

    DescriptionInput 包含6个用空格分割的m,a,c,X0,n和g,其中a,c,X0是非负整数,m,n,g是正整数. Output 输出一个数,即Xn mod gSample Input ...

  3. iOS开发网络编程之断点续传-NSURLConnection

    最近在做一个小项目的时候,发现使用NSURLSession或者AFNNetworking进行断点续传时诸多的不便,于是自己封装了一个类来实现断点续传,在程序重新启动时仍然可以继续下载(需自己调用方法) ...

  4. 2015年最新中国知网CNKI免费账号直接入口

    以下是Free9免费资源网小编收集整理的2015年最新中国知网CNKI免费账号直接入口,现免费分享给大家(仅供测试使用),此类文献数据库资源有时效性,希望对您的学习.工作上有所帮助! 中国知网直接入口 ...

  5. [转载]Spring Beans Auto-Wiring

    Autowiring Modes You have learnt how to declare beans using the <bean> element and inject < ...

  6. POJ 3440 Coin Toss(求概率)

    题目链接 题意 :把硬币往棋盘上扔,分别求出硬币占1,2,3,4个格子的时候的概率. 思路 : 求出公式输出,不过要注意输出格式,我还因为输入的时候用了int类型错了好几次..... #include ...

  7. *[topcoder]ChooseTheBestOne

    https://www.topcoder.com/stat?c=problem_statement&pm=13146&rd=15852 // Need carefully calc t ...

  8. 【Linux高频命令专题(8)】五大查询命令

    find 格式 find 路径 -命令参数 [输出形式] 路径:告诉find在哪儿去找你要的东西 命令参数:参考下面 输出形式:输出形式很多,-print,-printf,-print,-exec,- ...

  9. python 利用imap接收邮件,并保存附件

    def SaveAttachImap():# login the imap server ,retrive the  new mails ,and download the attachments. ...

  10. 开源调度框架Quartz最佳实践

    开源调度框架Quartz最佳实践 Quartz是一个Java调度框架,当前的最新版本为2.2.1. 以Quartz 2.2.1版为例,Quartz最佳实践(用于生产系统)总结如下: 1.跳过更新检查Q ...