UVa 1400 (线段树) "Ray, Pass me the dishes!"
求一个区间的最大连续子序列,基本想法就是分治,这段子序列可能在区间的左半边,也可能在区间的右半边,也有可能是横跨区间中点,这样就是左子区间的最大后缀加上右子区间的最大前缀之和。
线段树维护三个信息:区间最大前缀、最大后缀、最大连续子区间的下标。
最大前缀可以通过递推来求:要么是左子区间的最大前缀和、要么是左子区间的和 加上 右子区间的最大前缀和
最大后缀和的递推类似。
递推之前要预处理整个序列的前缀和。
#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!"的更多相关文章
- UVA 1400 线段树
input n m 1<=n,m<=500000 a1 a2 ... an |ai|<=1e9 m行查询 每行一对a b output 对于每对a b输出区间[a,b]中最小连续和x ...
- UVA 1400."Ray, Pass me the dishes!" -分治+线段树区间合并(常规操作+维护端点)并输出最优的区间的左右端点-(洛谷 小白逛公园 升级版)
"Ray, Pass me the dishes!" UVA - 1400 题意就是线段树区间子段最大和,线段树区间合并,但是这道题还要求输出最大和的子段的左右端点.要求字典序最小 ...
- UVA 1400 1400 - "Ray, Pass me the dishes!"(线段树)
UVA 1400 - "Ray, Pass me the dishes!" option=com_onlinejudge&Itemid=8&page=show_pr ...
- UvaLA 3938 "Ray, Pass me the dishes!"
"Ray, Pass me the dishes!" Time Limit: 3000MS Memory Limit: Unkn ...
- 线段树(区间合并) LA 3989 "Ray, Pass me the dishes!"
题目传送门 题意:动态最大连续子序列和,静态的题目 分析:nlogn的归并思想.线段树维护结点的三个信息,最大前缀和,最大后缀和,该区间的最大和的两个端点,然后答案是三个的better.书上用pair ...
- uva 1400 - "Ray, Pass me the dishes!"
又是一道线段树区间更新的题: #include<cstdio> #include<algorithm> #include<cstring> #define ll l ...
- UVALive 3938 - "Ray, Pass me the dishes!" - [最大连续子列和+线段树]
题目链接:https://cn.vjudge.net/problem/UVALive-3938 参考刘汝佳书上说的: 题意: 给出一个长度为n的序列, 再给出m个询问, 每个询问是在序列 $[a,b] ...
- uva 11525(线段树)
题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- UVA 11297 线段树套线段树(二维线段树)
题目大意: 就是在二维的空间内进行单个的修改,或者进行整块矩形区域的最大最小值查询 二维线段树树,要注意的是第一维上不是叶子形成的第二维线段树和叶子形成的第二维线段树要 不同的处理方式,非叶子形成的 ...
随机推荐
- 打造自己的程序员品牌(摘自Infoq)
John Sonmez是Simple Programmer的创始人.作者与程序员,关注于如何让复杂的事情变得简单.他是一位专业的软件开发者.架构师与讲师,感兴趣的领域包括测试驱动开发.如何编写整洁的代 ...
- c++ uuid生成法则
http://www.jb51.net/LINUXjishu/39614.html CentOS #include <uuid/uuid.h> 找不到文件解决方法: sudo yum in ...
- angular入门系列教程2
主题: 本篇主要介绍下angular里的一些概念,并且在咱们的小应用上加上点料.. 概念(大概了解即可,代码中遇到的会有详细注释): 模板:动态模板,是动态的,直接去处理DOM的,而不是通过处理字符串 ...
- shell 循环使用
问题描述: shell中for循环while循环的使用 问题解决: (1)for循环 (1.1)数 ...
- 2014 Multi-University Training Contest 6
官方解题报告:http://blog.sina.com.cn/s/blog_a19ad7a10102uz2v.html Apple Tree http://acm.hdu.edu.cn/showpro ...
- PhyreEngine3.8 MSAA resolution
There is something wrong in PhyreEngine 3.8 to fullfill MSAA, actually, I think it is eqaa You have ...
- failed creating the Direct3d device--debug
D3DDEVTYPE_REF 使用REF设备,用软件模拟Direct3D API 照理说是为了让电脑能跑本机不能硬件执行的渲染命令的 但我 pDeviceSettings->d3d9.Devic ...
- [设计模式] 9 装饰者模式 Decorator
转:http://www.jellythink.com/archives/171#prettyPhoto 什么是装饰模式? 在GOF的<设计模式:可复用面向对象软件的基础>一书中对装饰模式 ...
- 配置java环境
1.下载JDK http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html 2.下载之后ne ...
- 一个很吊的swing循环生成窗口。
import javax.swing.*; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; publi ...