1. 程式人生 > >UVA-1400 Ray, Pass me the dishes!

UVA-1400 Ray, Pass me the dishes!

span while 相交 scan rec text class {} oid

UVA-1400 Ray, Pass me the dishes!

題意:給出一個長度為n的整數序列D,有m個詢問,每個詢問(a,b)找到兩個下標x和y,使得a<=x<=y<=n,並且Dx+...+Dy盡量大。如果有多組滿足條件的x和y,x應該盡量小。如果還有多解,y應該盡量小。

思路:線段樹,對於一個區間,需要維護的值是這個區間的最大連續前綴和,後綴和以及最大連續和的數字下標出現位置。這樣,當找(a,b)的最大連續和的下標位置時,分三種情況:

1:最大連續和的起點和終點都在[a,mid)中

2:連續和的起點終點都在[mid,b)中

3:起點在[a,mid)中,終點在[mid,b)中,這樣最大連續和就是以mid為終點的[a,mid)的後綴和+以mid為起點的[mid,b)的前綴和,遞歸查找連續和的起點終點即可。

具體參考《算法競賽入門經典——訓練指南》P202

AC代碼:

#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>
#include <string>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define MAX 0x7ffffffffffffff
typedef long long ll;
const int N_MAX = 500000
+20; int D[N_MAX]; ll presum[N_MAX]; int n, m; struct MAX_sum { ll data;int L, R; MAX_sum(ll data = 0, int L = 0, int R = 0) :data(data), L(L), R(R) {} }max_sum[2 * N_MAX]; struct MAX_prefix { ll data;int R; MAX_prefix(ll data = 0, int R = 0) :data(data), R(R) {} }max_prefix[2 * N_MAX]; struct
MAX_suffix { ll data;int L; MAX_suffix(ll data = 0, int L = 0) :data(data), L(L) {} }max_suffix[2 * N_MAX]; ll sum(int l,int r) {//計算區間[l,r)的和 if (l == 0)return presum[r-1]; else return presum[r-1] - presum[l - 1]; } MAX_sum better(MAX_sum a,MAX_sum b) { if (a.data != b.data)return a.data > b.data ? a : b; else if (a.L != b.L)return a.L < b.L ? a : b; else return a.R < b.R ? a : b; } void segtree_init(int k, int l, int r) {//區間[l,r) if (r - l == 1) { max_prefix[k] = MAX_prefix(D[l], l); max_suffix[k] = MAX_suffix(D[l], l); max_sum[k] = MAX_sum(D[l], l, l); } else { int mid = (l + r) >> 1, chl = (k << 1) + 1, chr = (k << 1) + 2; segtree_init(chl, l, mid); segtree_init(chr, mid, r); if (max_prefix[chl].data >= sum(l,mid) + max_prefix[chr].data) max_prefix[k] = max_prefix[chl]; else max_prefix[k] = MAX_prefix(sum(l,mid) + max_prefix[chr].data, max_prefix[chr].R); if (max_suffix[chr].data > max_suffix[chl].data + sum(mid,r)) max_suffix[k] = max_suffix[chr]; else max_suffix[k] = MAX_suffix(sum(mid,r) + max_suffix[chl].data, max_suffix[chl].L); max_sum[k] = better(max_sum[chl],max_sum[chr]); max_sum[k] = better(max_sum[k], MAX_sum(max_suffix[chl].data + max_prefix[chr].data, max_suffix[chl].L, max_prefix[chr].R)); } } MAX_prefix seg_pre_query(int a, int b, int k, int l, int r) { if (a <= l&&b >= r) { return max_prefix[k]; } else if (a >= r || b <= l) {//完全不相交 return MAX_prefix(-MAX, INF); } else { int chl = (k << 1) + 1, chr = (k << 1) + 2, mid = (l + r) >> 1; MAX_prefix p1=seg_pre_query(a, b, chl, l, mid); MAX_prefix p2=seg_pre_query(a, b, chr, mid, r); return p1.data >= p2.data + sum(l, mid) ? p1 : MAX_prefix(p2.data + sum(l, mid), p2.R); } } MAX_suffix seg_suf_query(int a,int b,int k,int l,int r) { if (a <= l&&b >= r) { return max_suffix[k]; } else if (a >= r || b <= l) { return MAX_suffix(-MAX,INF); } else { int chl = (k << 1) + 1, chr = (k << 1) + 2, mid = (l + r) >> 1; MAX_suffix p1 = seg_suf_query(a, b, chl, l, mid); MAX_suffix p2 = seg_suf_query(a, b, chr, mid, r); return p2.data > p1.data + sum(mid, r) ? p2 : MAX_suffix(p1.data + sum(mid, r), p1.L); } } MAX_sum seg_query(int a, int b, int k, int l, int r) { if (a <= l&&b >= r) { return max_sum[k]; } else if (a >= r || b <= l) {//完全不相交 return MAX_sum(-MAX,INF,INF); } else { int mid = (l + r) >> 1, chl = (k << 1) + 1, chr = (k << 1) + 2; MAX_sum sum1 = seg_query(a, b, chl, l, mid); MAX_sum sum2 = seg_query(a, b, chr,mid, r); MAX_prefix pre = seg_pre_query(a, b, chr, mid, r);//mid一定在[a,b)區間當中 MAX_suffix suf = seg_suf_query(a, b, chl, l, mid);//同理 MAX_sum sum3 = MAX_sum(pre.data + suf.data, suf.L, pre.R); MAX_sum SUM = better(sum1, sum2); SUM = better(SUM,sum3); return SUM; } } int main() { int Case = 0; while (scanf("%d%d",&n,&m)!=EOF) { for (int i = 0; i < n; i++) { scanf("%d", &D[i]); if (!i)presum[i] = D[i]; else presum[i] = presum[i - 1] + D[i]; } segtree_init(0,0,n); printf("Case %d:\n",++Case); for (int cs = 1; cs <= m; cs++) { int a, b; scanf("%d%d", &a, &b); a--; MAX_sum ans=seg_query(a,b,0,0,n); printf("%d %d\n",ans.L+1,ans.R+1); } } return 0; } /* 8 1 3 -4 1 3 -2 5 1 3 2 6 */

UVA-1400 Ray, Pass me the dishes!