sicily 1136 山海经

    题目地址: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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值