zoukankan      html  css  js  c++  java
  • LA 3938 动态最大连续和

    题目链接:https://vjudge.net/contest/146667#problem/C

    题意:动态的求一个区间的最大连续和。

    分析:

    看上去可以RMQ去做,但是,当分成两个部分,原来的部分的解可能是跨越这两个区间的。原问题的解不能通过RMQ分成的两个部分的解而得到。

    线段树:

    线段树很早之前就有学习,那个时候只会套模板,而这个题目几乎就是线段树的一个理解应用。

    就在刚刚之前提到的那个问题一样,可以利用线段树维护3个信息:

    max_prefix(最大前缀和的标号)

    max_suffix(最大后缀和的标号)

    有了这两个信息,就可以跨区间找到丢失的信息了。

    还有一个就是结果 max_sub(最大连续和的标号,其中是一个pair类型)

    建树时:

    建好左右子树后,递推max_prefix,max_suffix,这两个都不用跨区间,递推max_sub需要跨区间。

    这里没有更新操作。

    询问时:

    同样分三种情况,左半边,右半边,跨区间。

    跨区间这里,就用到了我们之前维护的最大前缀和标号,和最大后缀和标号。

    那么如何得到最大前缀和标号,和最大后缀和标号呢?

    同理:也是分区间查找,但是右半部分的左边的标号必须是L,左半部分简单一点,就是左孩子的最大前缀和的标号。

    同理最大后缀和的标号。

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 const int maxn = 500000 + 10;
      6 const int maxnode = 1000000 + 10;
      7 typedef long long LL;
      8 typedef pair<int,int> Interval;
      9 
     10 LL prefix_sum[maxn];
     11 
     12 //求区间和
     13 LL sum(int L,int R) {
     14     return prefix_sum[R] - prefix_sum[L-1];
     15 }
     16 
     17 //求区间和
     18 LL sum(Interval p) {
     19     return sum(p.first,p.second);
     20 }
     21 
     22 Interval better(Interval a,Interval b) {
     23     if(sum(a)!=sum(b)) return sum(a) > sum(b) ? a : b;
     24     return a<b? a:b;
     25 }
     26 
     27 int qL,qR;
     28 
     29 struct IntervalTree
     30 {
     31     int max_prefix[maxnode];    //最大前缀和对应的标号
     32     int max_suffix[maxnode];    //最大后缀和对应的标号
     33     Interval max_sub[maxnode];  //最大连续和对应的起点和终点
     34 
     35     void build(int o,int L,int R)
     36     {
     37         if(L==R)
     38         {
     39             max_prefix[o] = max_suffix[o] = L;
     40             max_sub[o] = make_pair(L,L);
     41         }
     42         else
     43         {
     44             int M = L+(R-L)/2;
     45             int lc = o*2,rc = o*2+1;
     46             build(lc,L,M);
     47             build(rc,M+1,R);
     48 
     49             //递推最大前缀和
     50             LL v1 = sum(L,max_prefix[lc]);
     51             LL v2 = sum(L,max_prefix[rc]);
     52             if(v1==v2) max_prefix[o] = min(max_prefix[lc],max_prefix[rc]);
     53             else max_prefix[o] = v1 > v2 ? max_prefix[lc] : max_prefix[rc];
     54 
     55             //递推最大后缀和
     56             v1 = sum(max_suffix[lc],R);
     57             v2 = sum(max_suffix[rc],R);
     58             if(v1==v2) max_suffix[o] = min(max_suffix[lc],max_suffix[rc]);
     59             else max_suffix[o] = v1 > v2 ? max_suffix[lc] : max_suffix[rc];
     60 
     61             //递推最大连续和
     62             max_sub[o] = better(max_sub[lc],max_sub[rc]);
     63             max_sub[o] = better(max_sub[o],make_pair(max_suffix[lc],max_prefix[rc]));
     64         }
     65     }
     66 
     67     //求最大前缀和的那个区间
     68     Interval query_prefix(int o,int L,int R)
     69     {
     70         if(max_prefix[o]<=qR) return make_pair(L,max_prefix[o]);
     71         int M = L + (R-L)/2;
     72         int lc = o*2,rc = o*2 + 1;
     73         if(qR<=M) return query_prefix(lc,L,M);
     74         Interval i = query_prefix(rc,M+1,R);
     75         i.first = L;
     76         return better(i,make_pair(L,max_prefix[lc]));
     77     }
     78 
     79 
     80     Interval query_suffix(int o,int L,int R)
     81     {
     82         if(max_suffix[o]>=qL) return make_pair(max_suffix[o],R);
     83         int M = L + (R-L) /2;
     84         int lc = o*2,rc = o*2+1;
     85         if(qL>M) return query_suffix(rc,M+1,R);
     86         Interval i = query_suffix(lc,L,M);
     87         i.second = R;
     88         return better(i,make_pair(max_suffix[rc],R));
     89 
     90     }
     91 
     92     Interval query(int o,int L,int R)
     93     {
     94         if(qL<=L&&R<=qR) return max_sub[o];
     95         int M = L + (R - L) /2;
     96         int lc = o*2,rc = o*2+1;
     97         if(qR<=M) return query(lc,L,M);
     98         if(qL>M) return query(rc,M+1,R);
     99         Interval i1 = query_prefix(rc,M+1,R);
    100         Interval i2 = query_suffix(lc,L,M);
    101         Interval i3 = better(query(lc,L,M),query(rc,M+1,R));    //分开
    102         return better(make_pair(i2.first,i1.second),i3);        //跨区间
    103     }
    104 
    105 };
    106 
    107 IntervalTree tree;
    108 
    109 int main()
    110 {
    111     int n,q,a;
    112     int cases = 1;
    113     while(scanf("%d%d",&n,&q)==2)
    114     {
    115         prefix_sum[0] = 0;
    116         for(int i=0; i<n; i++)
    117         {
    118             scanf("%d",&a);
    119             prefix_sum[i+1] = prefix_sum[i] + a;
    120         }
    121         tree.build(1,1,n);
    122         printf("Case %d:
    ",cases++);
    123 
    124         while(q--) {
    125             int L,R;
    126             scanf("%d%d",&L,&R);
    127             qL = L;
    128             qR = R;
    129             Interval ans = tree.query(1,1,n);
    130             printf("%d %d
    ",ans.first,ans.second);
    131         }
    132 
    133 
    134     }
    135 
    136     return 0;
    137 }
  • 相关阅读:
    Android Dalvik 虚拟机
    我在北京找工作(二):java实现算法<1> 冒泡排序+直接选择排序
    如何用java比较两个时间或日期的大小
    [安卓破解]听网页浏览器,无需注册即可语音朗读
    (step8.2.4)hdu 1846(Brave Game——巴什博奕)
    Oracle Database 12c Release 1 Installation On Oracle Linux 6.4 x86_64
    HDU2084:数塔(DP)
    MySQL MVCC(多版本并发控制)
    POJ
    网易前端微专业,JavaScript程序设计基础篇:数组
  • 原文地址:https://www.cnblogs.com/TreeDream/p/6308520.html
Copyright © 2011-2022 走看看