UVa 1400 (线段树) Ray, Pass me the dishes!
求一个区间的最大连续子序列,基本想法就是分治,这段子序列可能在区间的左半边,也可能在区间的右半边,也有可能是横跨区间中点,这样就是左子区间的最大后缀加上右子区间的最大前缀之和。
线段树维护三个信息:区间最大前缀、最大后缀、最大连续子区间的下标。
最大前缀可以通过递推来求:要么是左子区间的最大前缀和、要么是左子区间的和 加上 右子区间的最大前缀和
最大后缀和的递推类似。
递推之前要预处理整个序列的前缀和。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define MP make_pair 5 #define lch(o) (o*2) 6 #define rch(o) (o*2+1) 7 using namespace std; 8 9 typedef long long LL; 10 typedef pair<int, int> Interval; 11 const int maxn = 500000 + 10; 12 const int maxnode = 1000000 + 10; 13 14 LL prefix_sum[maxn]; 15 16 LL sum(int a, int b) { return prefix_sum[b] - prefix_sum[a-1]; } 17 18 LL sum(Interval p) { return sum(p.first, p.second); } 19 20 Interval better(Interval a, Interval b) 21 { 22 if(sum(a) != sum(b)) return sum(a) > sum(b) ? a : b; 23 return a < b ? a : b; //pair自带字典序 24 } 25 26 int qL, qR; //查询区间 27 28 struct IntervalTree 29 { 30 int max_prefix[maxnode], max_suffix[maxnode]; 31 Interval max_sub[maxnode]; 32 33 void build(int o, int L, int R) 34 { 35 if(L == R) { max_prefix[o] = max_suffix[o] = L; max_sub[o] = MP(L, L); } 36 else 37 { 38 int M = (L + R) >> 1; 39 int lc = lch(o), rc = rch(o); 40 build(lc, L, M); 41 build(rc, M+1, R); 42 43 //递推max_prefix 44 LL v1 = sum(L, max_prefix[lc]); 45 LL v2 = sum(L, max_prefix[rc]); 46 if(v1 == v2) max_prefix[o] = min(max_prefix[lc], max_prefix[rc]); 47 else max_prefix[o] = v1 > v2 ? max_prefix[lc] : max_prefix[rc]; 48 49 //递推max_suffix 50 v1 = sum(max_suffix[lc], R); 51 v2 = sum(max_suffix[rc], R); 52 if(v1 == v2) max_suffix[o] = min(max_suffix[lc], max_suffix[rc]); 53 else max_suffix[o] = v1 > v2 ? max_suffix[lc] : max_suffix[rc]; 54 55 //递推max_sub 56 max_sub[o] = better(max_sub[lc], max_sub[rc]); 57 max_sub[o] = better(max_sub[o], MP(max_suffix[lc], max_prefix[rc])); 58 } 59 } 60 61 Interval query_prefix(int o, int L, int R) 62 { 63 if(max_prefix[o] <= qR) return MP(L, max_prefix[o]); 64 int M = (L + R) >> 1; 65 int lc = lch(o), rc = rch(o); 66 if(qR <= M) return query_prefix(lc, L, M); 67 Interval i = query_prefix(rc, M+1, R); 68 i.first = L; 69 return better(i, MP(L, max_prefix[lc])); 70 } 71 72 Interval query_suffix(int o, int L, int R) 73 { 74 if(max_suffix[o] >= qL) return MP(max_suffix[o], R); 75 int M = (L + R) >> 1; 76 int lc = lch(o), rc = rch(o); 77 if(qL > M) return query_suffix(rc, M+1, R); 78 Interval i = query_suffix(lc, L, M); 79 i.second = R; 80 return better(i, MP(max_suffix[rc], R)); 81 } 82 83 Interval query(int o, int L, int R) 84 { 85 if(qL <= L && R <= qR) return max_sub[o]; 86 int M = (L + R) >> 1; 87 int lc = lch(o), rc = rch(o); 88 if(qR <= M) return query(lc, L, M); 89 if(qL > M) return query(rc, M+1, R); 90 Interval i1 = query_suffix(lc, L, M);//左子区间的最大后缀 91 Interval i2 = query_prefix(rc, M+1, R);//右子区间的最大前缀 92 Interval i3 = better(query(lc, L, M), query(rc, M+1, R));//两个子区间的最大连续和 93 return better(i3, MP(i1.first, i2.second)); 94 } 95 }tree; 96 97 int main() 98 { 99 //freopen("in.txt", "r", stdin); 100 101 int kase = 0, n, a, Q; 102 while(scanf("%d%d", &n, &Q) == 2) 103 { 104 prefix_sum[0] = 0; 105 for(int i = 1; i <= n; i++) { scanf("%d", &a); prefix_sum[i] = prefix_sum[i-1] + a; } 106 tree.build(1, 1, n); 107 printf("Case %d:\n", ++kase); 108 while(Q--) 109 { 110 int L, R; 111 scanf("%d%d", &L, &R); 112 qL = L; qR = R; 113 Interval ans = tree.query(1, 1, n); 114 printf("%d %d\n", ans.first, ans.second); 115 } 116 } 117 118 return 0; 119 }
代码君
转载于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4356495.html
UVa 1400 (线段树) Ray, Pass me the dishes!相关推荐
- 线段树(区间合并) LA 3989 Ray, Pass me the dishes!
题目传送门 题意:动态最大连续子序列和,静态的题目 分析:nlogn的归并思想.线段树维护结点的三个信息,最大前缀和,最大后缀和,该区间的最大和的两个端点,然后答案是三个的better.书上用pair ...
- UVA - 11992 线段树
UVA - 11992 题意:有一个 r*c 的全 0矩阵, 进行 3 种操作. 1 x1 y1 x2 y2 val 表示将(x1,y1,x2,y2)(x1<=x2,y1<=y2)子矩阵中 ...
- UVa 11992 (线段树 区间修改) Fast Matrix Operations
比较综合的一道题目. 二维的线段树,支持区间的add和set操作,然后询问子矩阵的sum,min,max 写完这道题也是醉醉哒,代码仓库里还有一份代码就是在query的过程中也pushdown向下传递 ...
- uva 12086 线段树or树状数组练习
题目链接 https://vjudge.net/problem/34215/origin 这个题就是线段树裸题,有两种操作,实现单点更新和区间和的查找即可,这里第一次学习使用树状数组完成. 二者相 ...
- UVALive - 3938 Ray, Pass me the dishes!
注意分清三种情况,并且保证字典序最小 #include <cstdio> #include <cstring> #include <algorithm> #incl ...
- UVA 12501 Bulky process of bulk reduction ——(线段树成段更新)
和普通的线段树不同的是,查询x~y的话,给出的答案是第一个值的一倍加上第二个值的两倍一直到第n个值的n倍. 思路的话,就是关于query和pushup的方法.用一个新的变量sum记录一下这个区间里面按 ...
- UVa 1471 Defense Lines - 线段树 - 离散化
题意是说给一个序列,删掉其中一段连续的子序列(貌似可以为空),使得新的序列中最长的连续递增子序列最长. 网上似乎最多的做法是二分查找优化,然而不会,只会值域线段树和离散化... 先预处理出所有的点所能 ...
- UVA 12086 Potentiometers(线段树裸题)
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...
- 线段树(多维+双成段更新) UVA 11992 Fast Matrix Operations
题目传送门 题意:训练指南P207 分析:因为矩阵不超过20行,所以可以建20条线段的线段树,支持两个区间更新以及区间查询. #include <bits/stdc++.h> using ...
最新文章
- 这交互炸了 - 收藏集 - 掘金
- SilverLigth的Chart不要图例(Legend)的方法
- wxWidgets:wxMenuItem类用法
- SAP Spartacus B2B页面unit tree取数据的设计逻辑
- mongodb插入速度每秒_MongoDB事实:商品硬件上每秒插入80000次以上
- [html] 如何放大点击的区域?
- [手把手教]discuzX2插件制作教程__最菜鸟级别的入门坎 【三】
- 在 TMG 更新中心中使用 WSUS进行每日的定义更新
- php 数组作用域,如何在php中访问私有作用域命名空间数组数据?
- Netty工作笔记0053---Netty核心模块梳理
- 《C++程序设计语言(特别版)》——忠告
- CAS Tomcat实现单点登录
- java opencv去除干扰线_电子产品硬件研发—提高抗干扰性能的常用方法
- 网络规划设计方案(模板)
- 【工具向】分析FGUI依赖关系工具
- QImage类详解(QImage类型转换、QImage类函数及QImage像素操作)
- win10系统升级后mysql找不到服务及数据消失问题
- 混合颜色带(基础篇)
- char *与char []的区别
- JRE和JDK的区别?