题目链接
题意: 给你一个序列 (n <= 500000), 求其动态最大子段和的左右两端下标(x,y),询问(q <= 500000), 注意一定要取一个数,如果最大和相等 取x最小的那段,又如果x相等,取y最小的那段。
如果只求和,那么这题还算比较顺手, 但求下标,节点保存的数据比较多,导致更新的时候很容易出错,其实题目本身还是很容易想到的,只是比较麻烦,锻炼查错能力。
思路;
对于某一区间最值的更新:
1. 左区间的最值
2 右区间的最值
3 左区间的最大后缀和 + 右区间的最大前缀和
对于最大前缀和的更新:
1 左区间的最大前缀和
2 左区间的和 + 右区间的最大前缀和
对于最大后缀和的更新: 类似前缀
下标在更新最值,最大前缀,最大后缀 时 一同更新。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 500005 #define lc rt<<1 #define rc rt<<1|1 #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define mid int m = (l + r) >> 1 #define LL long long int n; struct node { LL sum, max, lsum, rsum; // 区间和,最大值,最大前缀和,最大后缀和 int l, r, ll, rr; // 最大区间左右端点, 最大前缀和端点, 最大后缀和端点 }a[maxn<<2]; void pushup(int l, int r, int rt) { mid; a[rt].sum = a[lc].sum + a[rc].sum; // sum a[rt].lsum = a[lc].lsum; a[rt].rsum = a[rc].rsum; //lsum, rsum a[rt].ll = a[lc].ll; a[rt].rr = a[rc].rr; if(a[lc].sum + a[rc].lsum > a[rt].lsum ) a[rt].lsum = a[lc].sum + a[rc].lsum, a[rt].ll = a[rc].ll; if(a[rc].sum + a[lc].rsum >= a[rt].rsum ) a[rt].rsum = a[rc].sum + a[lc].rsum, a[rt].rr = a[lc].rr; int tp; // max, l, r if(a[lc].max >= a[rc].max) tp = lc; else tp = rc; a[rt].max = a[tp].max; a[rt].l = a[tp].l; a[rt].r = a[tp].r; LL tt = a[lc].rsum + a[rc].lsum; if(tt > a[rt].max || tt == a[rt].max && a[rt].l > a[lc].rr || tt == a[rt].max && a[rt].l == a[lc].rr && a[rt].r > a[rc].ll) a[rt].max = tt, a[rt].l = a[lc].rr, a[rt].r = a[rc].ll; } void build(int l=1, int r=n, int rt=1) { if(l == r) { scanf("%lld", &a[rt].sum); a[rt].max = a[rt].lsum = a[rt].rsum = a[rt].sum; a[rt].l = a[rt].r = a[rt].ll = a[rt].rr = l; return; } mid; build(lson); build(rson); pushup(l, r, rt); /* printf("l = %d r = %d\n", l, r); printf("max = %lld sum = %lld lsum = %lld rsum = %lld\n", a[rt].max, a[rt].sum, a[rt].lsum, a[rt].rsum); printf("~~~~~~l = %d r = %d ll = %d rr = %d\n", a[rt].l, a[rt].r, a[rt].ll, a[rt].rr); */ } node query(int L, int R, int l=1, int r=n, int rt=1) { if(L == l && r == R) return a[rt]; mid; if(L > m) return query(L, R, rson); else if(R <= m) return query(L, R, lson); else { node t1 = query(L, m, lson); node t2 = query(m+1, R, rson); /* printf("query: l = %d r = %d m = %d\n", l, r, m); printf("max = %lld sum = %lld lsum = %lld rsum = %lld\n", t1.max, t1.sum, t1.lsum, t1.rsum); printf("!!!!l = %d r = %d ll = %d rr = %d\n", t1.l, t1.r, t1.ll, t1.rr); puts(""); printf("max = %lld sum = %lld lsum = %lld rsum = %lld\n", t2.max, t2.sum, t2.lsum, t2.rsum); printf("!!!!l = %d r = %d ll = %d rr = %d\n", t2.l, t2.r, t2.ll, t2.rr); */ node ret; ret.sum = t1.sum + t2.sum; // sum if(t1.max >= t2.max) ret = t1; // max else ret = t2; LL tt = t1.rsum + t2.lsum; if(tt > ret.max || tt == ret.max && t1.rr < ret.l || tt == ret.max && t1.rr == ret.l && t2.ll < ret.r) ret.max = tt, ret.l = t1.rr, ret.r = t2.ll; ret.lsum = t1.lsum; ret.rsum = t2.rsum; // lsum, rsum ret.ll = t1.ll; ret.rr = t2.rr; if(t1.sum + t2.lsum > ret.lsum ) ret.lsum = t1.sum + t2.lsum, ret.ll = t2.ll; if(t2.sum + t1.rsum >= ret.rsum ) ret.rsum = t2.sum + t1.rsum, ret.rr = t1.rr; return ret; } } int main() { int i, j, cas = 1, m; while( ~scanf("%d%d", &n, &m)) { build(); printf("Case %d:\n", cas++); int x, y; while(m--) { scanf("%d%d", &x, &y); node t = query(x, y); printf("%d %d\n", t.l, t.r); } } return 0; } /* 8 100 -2 3 4 -6 6 10 -7 100 */