题目地址:http://soj.me/1136(这是一道虐了我几天的题目)
一开始看到这道题,顿时欣喜不少,发现就是最大子数组问题,但是看看数据,就吓尿了,真心觉得常规解法过不了(但还是抱着试试的态度写了,结果直接time limited了),想了好久没头绪,果断google之,发现了一个叫做线段树的东西。
这里先推荐这篇博客(我最终从这里走出了误区):http://blog.csdn.net/lifajun90/article/details/8190443。
当然我一开始是看到的这篇:http://blog.csdn.net/fanfank/article/details/8930394这篇有一个地方误导了我好久(lmax和rmax那里没说是保存在哪个节点,我根据上下文就理解错误了)。
据我所理解的线段树,就是要查询的区间分成很多子区间,然后把子区间的合并到一个区间,关键就是合并这个过程比较难(ps:如果是求子区间的最大数,那就当简单了,直接父节点 = max(左节点,右节点)),这道题的合并第一个博客利用了前面的一个函数,当然第二篇博客原理也是一样。下面附上我的代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#define MAX 111111
#define leftson l, m, (l+r) >> 1
#define rightson m+1, r, (l+r) >> 1 | 1
using namespace std;
struct Node {
int sum;
int sl, sr, smax;
int ll, lmax, rr, rmax;
};
Node n[MAX*4];
int count_;
int a[MAX];
Node pushUp(int root, int lson, int rson) {
n[root].sum = n[lson].sum + n[rson].sum;
int temp = n[rson].lmax + n[lson].sum;
if (temp > n[lson].lmax) {
n[root].lmax = temp;
n[root].ll = n[rson].ll;
} else {
n[root].lmax = n[lson].lmax;
n[root].ll = n[lson].ll;
}
temp = n[rson].sum + n[lson].rmax;
if (temp >= n[rson].rmax) {
n[root].rmax = temp;
n[root].rr = n[lson].rr;
} else {
n[root].rmax = n[rson].rmax;
n[root].rr = n[rson].rr;
}
n[root].smax = n[lson].smax;
n[root].sl = n[lson].sl;
n[root].sr = n[lson].sr;
temp = n[lson].rmax + n[rson].lmax;
if (temp > n[root].smax || (temp == n[root].smax && n[lson].rr < n[root].sl)) {
n[root].smax = temp;
n[root].sl = n[lson].rr;
n[root].sr = n[rson].ll;
}
if (n[rson].smax > n[root].smax) {
n[root].smax = n[rson].smax;
n[root].sl = n[rson].sl;
n[root].sr = n[rson].sr;
}
return n[root];
}
void build(int l, int r, int root) {
if (l == r) {
n[root].smax = n[root].rmax = n[root].lmax = n[root].sum = a[l];
n[root].ll = n[root].sl = l;
n[root].rr = n[root].sr = r;
return;
}
int m = (l + r) >> 1;
build(l, m, root*2);
build(m+1, r, root*2+1);
pushUp(root, root*2, root*2+1);
}
int query(int s, int e, int l, int r, int root) {
if (s <= l && e >= r) {
return root;
}
int m = (l + r) >> 1;
if ( e <= m) {
return query(s, e, l, m, root*2);
} else if (s > m) {
return query(s, e, m+1, r, root*2+1);
} else {
int temp1 = query(s, e, l, m, root*2);
int temp2 = query(s, e, m+1, r, root*2+1);
int k = count_++;
pushUp(k, temp1, temp2);
return k;
}
}
int main() {
int n1, n2;
scanf("%d%d", &n1, &n2);
for (int i = 1; i <= n1; i++)
scanf("%d", a+i);
build(1, n1, 1);
while (n2--) {
int start, end;
scanf("%d%d", &start, &end);
count_ = 3*n1+1;
int index = query(start, end, 1, n1, 1);
printf("%d %d %d\n", n[index].sl, n[index].sr, n[index].smax);
}
//system("pause");
return 0;
}
最后再送上一个学线段树的好地址:http://www.notonlysuccess.com/index.php/segment-tree-complete/