zoukankan      html  css  js  c++  java
  • 山海经 (线段树)

    前几天看mike的ppt发现有线段树的题,就挑了第一道题搞搞吧,然后就gg了,花了三天时间总算搞掉了

    先放题:

    775. 山海经

    ★★★☆   输入文件:hill.in   输出文件:hill.out   简单对比
    时间限制:1 s   内存限制:128 MB

    【问题描述】

    “南山之首日鹊山。其首日招摇之山,临于西海之上,多桂,多金玉。有草焉,其状如韭而青华,其名日祝余,食之不饥……又东三百里,日堂庭之山,多棪木,多白猿,多水玉,多黄金。

    又东三百八十里,日猨翼之山,其中多怪兽,水多怪鱼,多白玉,多蝮虫,多怪蛇,名怪木,不可以上。……”

    《山海经》是以山为纲,以海为线记载古代的河流、植物、动物及矿产等情况,而且每一条记录路线都不会有重复的山出现。某天,你的地理老师想重游《山海经》中的路线,为了简化问题,老师已经把每座山用一个整数表示他对该山的喜恶程度,他想知道第a座山到第b座山的中间某段路(i,j)。能使他感到最满意,即(i,j)这条路上所有山的喜恶度之和是(c,d)(a≤c≤d≤b)最大值。于是老师便向你请教,你能帮助他吗?值得注意的是,在《山海经》中,第i座山只能到达第i+1座山。

    【输入】

    输入第1行是两个数,n,m,2≤n≤100000,1≤m≤100000,n表示一共有n座山,m表示老师想查询的数目。

    第2行是n个整数,代表n座山的喜恶度,绝对值均小于10000。

    以下m行每行有a,b两个数,1≤a≤j≤b≤m,表示第a座山到第b座山。

    【输出】

    一共有m行,每行有3个数i,j,s,表示从第i座山到第j座山总的喜恶度为s。显然,对于每个查询,有a≤i≤j≤b,如果有多组解,则输出i最小的,如果i也相等,则输出j最小的解。

    【输入样例】

    5 3

    5 -6 3 -1 4

    1 3

    1 5

    5 5

    【输出样例】

    1 1 5

    3 5 6

    5 5 4

    这道题是真的毒瘤啊,简直就是求最大子段和的魔改版,先后问了许多大佬,先膜拜一下,orz,tql

    进入正题:

    一、本题基础是线段树求最大子段和

    那么如何求最大子段和呢?

    线段树核心就是push_up向上回溯的过程,主要是对其进行维护

    这样我们得出每个节点必要的三个信息:1、从左端点开始的最大前缀和 2、从右端点开始的最大后缀和 3、中间段的最大子段和

    维护的办法我们细说一下

    每个最大前缀和有两种情况

    1、是左儿子的最大前缀和 2、是左儿子的区间总和加上右儿子的最大前缀和

    同理最大后缀和也有两种情况

    1、是右儿子的最大后缀和 2、是右儿子的区间总和加上左儿子的最大后缀和

    那么中间的怎么搞,画图可知有三种情况

    1、是左儿子的中间最大子段和 2、是右儿子的中间最大子段和 3、是左儿子的最大后缀和加上右儿子的最大前缀和

    经过上面的分析就可以得出来push_up函数了

    附上丑丑的代码

    #define ls(x) x<<1
    #define rs(x) x<<1|1
    struct node
    { int sum,ls,rs,ms;} st[1000010];
    void push_up(int p)
    { st[p].sum=st[ls(p)].sum+st[rs(p)].sum;
      st[p].ls=max(st[ls(p)].ls,st[ls(p)].sum+st[rs(p)].ls);
      st[p].rs=max(st[rs(p)].rs,st[rs(p)].sum+st[ls(p)].rs);
      st[p].ms=max(st[ls(p)].ms,st[rs(p)].ms);
      st[p].ms=max(st[p].ms,st[ls(p)].rs+st[rs(p)].ls);  
    }

    二、本题就毒瘤在这了,他要输出最大子段和的序号,真的恶心

    我们就得想法啊,那么每个节点需要维护的信息还要加上最大中间子段和的左端点,右端点

    三、然而这还不够他还要按字典序输出,那么还要加上最大前缀和的右节点,最大后缀和的左节点

    最后就是线段树基本操作了

    贴代码

    #include<bits/stdc++.h>
    #define ls(x) x<<1
    #define rs(x) x<<1|1
    using namespace std;
    const int N=200010;
    int m,n,k,p,a[N];
    struct node
    { int ls,rs,ms;//ls从左节点开始的最大值,rs是右节点,ms总共的 
      int l,r,s;//l是区间左节点,r是右节点,s是区间和 
      int ml,mr;//ml是最大值区间左节点,mr是右节点 
      int ll,rr;
    } st[N<<2];
    void push_up(int p)
    { st[p].s=st[ls(p)].s+st[rs(p)].s;
      if (st[ls(p)].ls>=st[rs(p)].ls+st[ls(p)].s) {st[p].ls=st[ls(p)].ls;st[p].rr=st[ls(p)].rr;}
      else {st[p].ls=st[ls(p)].s+st[rs(p)].ls;st[p].rr=st[rs(p)].rr;}
      
      if (st[rs(p)].rs>=st[rs(p)].s+st[ls(p)].rs) {st[p].rs=st[rs(p)].rs;st[p].ll=st[rs(p)].ll;}
      else {st[p].rs=st[rs(p)].s+st[ls(p)].rs;st[p].ll=st[ls(p)].ll;}
      
      if (st[ls(p)].ms>=st[rs(p)].ms) {st[p].ms=st[ls(p)].ms;st[p].ml=st[ls(p)].ml;st[p].mr=st[ls(p)].mr;}
      else {st[p].ms=st[rs(p)].ms;st[p].ml=st[rs(p)].ml;st[p].mr=st[rs(p)].mr;}
      
      if (st[p].ms>st[ls(p)].rs+st[rs(p)].ls) return;
      if (st[p].ms<st[ls(p)].rs+st[rs(p)].ls) {st[p].ms=st[ls(p)].rs+st[rs(p)].ls;st[p].ml=st[ls(p)].ll;st[p].mr=st[rs(p)].rr;return;}
      
      if (st[p].ml<st[ls(p)].ll) return;
      if (st[p].ml>st[ls(p)].ll) {st[p].ml=st[ls(p)].ll;st[p].mr=st[rs(p)].rr;return;}
      
      st[p].mr=min(st[p].mr,st[rs(p)].rr);
    }
    void build(int l,int r,int p)
    { st[p].l=l;st[p].r=r;
      if (l==r) {st[p].ml=st[p].mr=st[p].ll=st[p].rr=l;
                 st[p].ls=st[p].rs=st[p].s=st[p].ms=a[l];
                 return;}
      int mid=(l+r)>>1;
      build (l,mid,ls(p));
      build (mid+1,r,rs(p));
      push_up(p);
    }
    node query(int nl,int nr,int p)
    { int l=st[p].l,r=st[p].r;
      if (nl<=l&&nr>=r) return st[p];
      int mid=(l+r)>>1;
      if (nr<=mid) return query(nl,nr,ls(p));
      if (nl>mid) return query(nl,nr,rs(p));
      node x,y,z;
      x=query(nl,nr,ls(p));y=query(nl,nr,rs(p));
      if (x.ls>=x.s+y.ls) {z.ls=x.ls;z.rr=x.rr;z.l=x.l;}
      else {z.ls=x.s+y.ls;z.rr=y.rr;z.l=x.l;}
      
      if (y.rs>=x.rs+y.s)  {z.rs=y.rs;z.ll=y.ll;z.r=y.r;}
      else  {z.rs=x.rs+y.s;z.ll=x.ll;z.r=y.r;}
      
      if (x.ms>=y.ms) {z.ms=x.ms;z.ml=x.ml;z.mr=x.mr;}
      else {z.ms=y.ms;z.ml=y.ml;z.mr=y.mr;}
      
      if (z.ms>x.rs+y.ls) return z;
      if (z.ms<x.rs+y.ls) {z.ms=x.rs+y.ls;z.ml=x.ll;z.mr=y.rr;return z;}
      
      if (z.ml<x.ll) return z;
      if (z.ml>x.ll) {z.ml=x.ll;z.mr=y.rr;return z;}
      
      z.mr=min(z.mr,y.rr);
      return z; 
    }
    int main()
    { freopen("hill.in","r",stdin);
      freopen("hill.out","w",stdout);
      scanf("%d%d",&n,&m);
      for (int i=1;i<=n;i++)
      scanf("%d",&a[i]);
      build(1,n,1);
      for (int i=1;i<=m;i++)
      { int x,y;
        scanf("%d%d",&x,&y);
        node tmp=query(x,y,1);
        printf("%d %d %d
    ",tmp.ml,tmp.mr,tmp.ms);
      }
      return 0;
    }

    愿hale越来越强

    慢即是快,细则是能,于小处铸迤逦
  • 相关阅读:
    Hihocoder #1014 : Trie树
    Codevs 1298 凸包周长
    洛谷 P1355 神秘大三角(计算几何基础)
    Cogs 1688. [ZJOI2008]树的统计Count(树链剖分+线段树||LCT)
    Poj 2887 Big String(块状数组)
    P1449 后缀表达式
    P3478 [POI2008]STA-Station
    P1533 可怜的狗狗
    P2073 送花
    P1014 Cantor表
  • 原文地址:https://www.cnblogs.com/Hale522520/p/10348538.html
Copyright © 2011-2022 走看看