uvalive 3938 "Ray, Pass me the dishes!" 线段树 区间合并
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uvalive 3938 "Ray, Pass me the dishes!" 线段树 区间合并相关的知识,希望对你有一定的参考价值。
题意:求q次询问的静态区间连续最大和起始位置和终止位置 输出字典序最小的解.
思路:刘汝佳白书 每个节点维护三个值
pre, sub, suf 最大的前缀和, 连续和, 后缀和 然后这个题还要记录解的位置所以还要区间总和sum
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstdio> 6 #include<set> 7 #include<map> 8 #include<vector> 9 #include<cstring> 10 #include<stack> 11 #include<cmath> 12 #include<queue> 13 #include <bits/stdc++.h> 14 using namespace std; 15 #define INF 0x3f3f3f3f 16 #define ll long long 17 #define clc(a,b) memset(a,b,sizeof(a)) 18 19 const int maxn = 500000 + 10; 20 const int maxnode = 1000000 + 10; 21 typedef long long LL; 22 typedef pair<int,int> Interval; 23 24 LL prefix_sum[maxn]; 25 26 LL sum(int L, int R) 27 { 28 return prefix_sum[R] - prefix_sum[L-1]; 29 } 30 31 LL sum(Interval p) 32 { 33 return sum(p.first, p.second); 34 } 35 36 Interval better(Interval a, Interval b) 37 { 38 if(sum(a) != sum(b)) return sum(a) > sum(b) ? a : b; 39 return a < b ? a : b; // 利用pair自带的字典序 40 } 41 42 int qL, qR; 43 44 struct IntervalTree 45 { 46 int max_prefix[maxnode]; 47 int max_suffix[maxnode]; 48 Interval max_sub[maxnode]; 49 50 void build(int o, int L, int R) 51 { 52 if(L == R) 53 { 54 max_prefix[o] = max_suffix[o] = L; 55 max_sub[o] = make_pair(L, L); 56 } 57 else 58 { 59 int M = L + (R-L)/2; 60 // 递归创建子树 61 int lc = o*2, rc = o*2+1; 62 build(lc, L, M); 63 build(rc, M+1, R); 64 65 // 递推max_prefix 66 LL v1 = sum(L, max_prefix[lc]); 67 LL v2 = sum(L, max_prefix[rc]); 68 if(v1 == v2) max_prefix[o] = min(max_prefix[lc], max_prefix[rc]); 69 else max_prefix[o] = v1 > v2 ? max_prefix[lc] : max_prefix[rc]; 70 71 // 递推max_suffix 72 v1 = sum(max_suffix[lc], R); 73 v2 = sum(max_suffix[rc], R); 74 if(v1 == v2) max_suffix[o] = min(max_suffix[lc], max_suffix[rc]); 75 else max_suffix[o] = v1 > v2 ? max_suffix[lc] : max_suffix[rc]; 76 77 // 递推max_sub 78 max_sub[o] = better(max_sub[lc], max_sub[rc]); // 完全在左子树或者右子树 79 max_sub[o] = better(max_sub[o], make_pair(max_suffix[lc], max_prefix[rc])); // 跨越中线 80 } 81 } 82 83 Interval query_prefix(int o, int L, int R) 84 { 85 if(max_prefix[o] <= qR) return make_pair(L, max_prefix[o]); 86 int M = L + (R-L)/2; 87 int lc = o*2, rc = o*2+1; 88 if(qR <= M) return query_prefix(lc, L, M); 89 Interval i = query_prefix(rc, M+1, R); 90 i.first = L; 91 return better(i, make_pair(L, max_prefix[lc])); 92 } 93 94 Interval query_suffix(int o, int L, int R) 95 { 96 if(max_suffix[o] >= qL) return make_pair(max_suffix[o], R); 97 int M = L + (R-L)/2; 98 int lc = o*2, rc = o*2+1; 99 if(qL > M) return query_suffix(rc, M+1, R); 100 Interval i = query_suffix(lc, L, M); 101 i.second = R; 102 return better(i, make_pair(max_suffix[rc], R)); 103 } 104 105 Interval query(int o, int L, int R) 106 { 107 if(qL <= L && R <= qR) return max_sub[o]; 108 int M = L + (R-L)/2; 109 int lc = o*2, rc = o*2+1; 110 if(qR <= M) return query(lc, L, M); 111 if(qL > M) return query(rc, M+1, R); 112 Interval i1 = query_prefix(rc, M+1, R); // 右半的前缀 113 Interval i2 = query_suffix(lc, L, M); // 左半的后缀 114 Interval i3 = better(query(lc, L, M), query(rc, M+1, R)); 115 return better(make_pair(i2.first, i1.second), i3); 116 } 117 }; 118 119 IntervalTree tree; 120 121 int main() 122 { 123 int kase = 0, n, a, Q; 124 while(scanf("%d%d", &n, &Q) == 2) 125 { 126 prefix_sum[0] = 0; 127 for(int i = 0; i < n; i++) 128 { 129 scanf("%d", &a); 130 prefix_sum[i+1] = prefix_sum[i] + a; 131 } 132 tree.build(1, 1, n); 133 printf("Case %d:\n", ++kase); 134 while(Q--) 135 { 136 int L, R; 137 scanf("%d%d", &L, &R); 138 qL = L; 139 qR = R; 140 Interval ans = tree.query(1, 1, n); 141 printf("%d %d\n", ans.first, ans.second); 142 } 143 } 144 return 0; 145 }
以上是关于uvalive 3938 "Ray, Pass me the dishes!" 线段树 区间合并的主要内容,如果未能解决你的问题,请参考以下文章
UVALive - 3938 分治,线段树,求动态最大连续和
矩阵快速幂+实际应用--P3390 模板矩阵快速幂,P3938 斐波那契