• UVa 1400 (线段树) "Ray, Pass me the dishes!"


    求一个区间的最大连续子序列,基本想法就是分治,这段子序列可能在区间的左半边,也可能在区间的右半边,也有可能是横跨区间中点,这样就是左子区间的最大后缀加上右子区间的最大前缀之和。

    线段树维护三个信息:区间最大前缀、最大后缀、最大连续子区间的下标。

    最大前缀可以通过递推来求:要么是左子区间的最大前缀和、要么是左子区间的和 加上 右子区间的最大前缀和

    最大后缀和的递推类似。

    递推之前要预处理整个序列的前缀和。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #define MP make_pair
      5 #define lch(o) (o*2)
      6 #define rch(o) (o*2+1)
      7 using namespace std;
      8 
      9 typedef long long LL;
     10 typedef pair<int, int> Interval;
     11 const int maxn = 500000 + 10;
     12 const int maxnode = 1000000 + 10;
     13 
     14 LL prefix_sum[maxn];
     15 
     16 LL sum(int a, int b) { return prefix_sum[b] - prefix_sum[a-1]; }
     17 
     18 LL sum(Interval p) { return sum(p.first, p.second); }
     19 
     20 Interval better(Interval a, Interval b)
     21 {
     22     if(sum(a) != sum(b)) return sum(a) > sum(b) ? a : b;
     23     return a < b ? a : b;    //pair自带字典序
     24 }
     25 
     26 int qL, qR; //查询区间
     27 
     28 struct IntervalTree
     29 {
     30     int max_prefix[maxnode], max_suffix[maxnode];
     31     Interval max_sub[maxnode];
     32 
     33     void build(int o, int L, int R)
     34     {
     35         if(L == R) { max_prefix[o] = max_suffix[o] = L; max_sub[o] = MP(L, L); }
     36         else
     37         {
     38             int M = (L + R) >> 1;
     39             int lc = lch(o), rc = rch(o);
     40             build(lc, L, M);
     41             build(rc, M+1, R);
     42 
     43             //递推max_prefix
     44             LL v1 = sum(L, max_prefix[lc]);
     45             LL v2 = sum(L, max_prefix[rc]);
     46             if(v1 == v2) max_prefix[o] = min(max_prefix[lc], max_prefix[rc]);
     47             else max_prefix[o] = v1 > v2 ? max_prefix[lc] : max_prefix[rc];
     48 
     49             //递推max_suffix
     50             v1 = sum(max_suffix[lc], R);
     51             v2 = sum(max_suffix[rc], R);
     52             if(v1 == v2) max_suffix[o] = min(max_suffix[lc], max_suffix[rc]);
     53             else max_suffix[o] = v1 > v2 ? max_suffix[lc] : max_suffix[rc];
     54 
     55             //递推max_sub
     56             max_sub[o] = better(max_sub[lc], max_sub[rc]);
     57             max_sub[o] = better(max_sub[o], MP(max_suffix[lc], max_prefix[rc]));
     58         }
     59     }
     60 
     61     Interval query_prefix(int o, int L, int R)
     62     {
     63         if(max_prefix[o] <= qR) return MP(L, max_prefix[o]);
     64         int M = (L + R) >> 1;
     65         int lc = lch(o), rc = rch(o);
     66         if(qR <= M) return query_prefix(lc, L, M);
     67         Interval i = query_prefix(rc, M+1, R);
     68         i.first = L;
     69         return better(i, MP(L, max_prefix[lc]));
     70     }
     71 
     72     Interval query_suffix(int o, int L, int R)
     73     {
     74         if(max_suffix[o] >= qL) return MP(max_suffix[o], R);
     75         int M = (L + R) >> 1;
     76         int lc = lch(o), rc = rch(o);
     77         if(qL > M) return query_suffix(rc, M+1, R);
     78         Interval i = query_suffix(lc, L, M);
     79         i.second = R;
     80         return better(i, MP(max_suffix[rc], R));
     81     }
     82 
     83     Interval query(int o, int L, int R)
     84     {
     85         if(qL <= L && R <= qR) return max_sub[o];
     86         int M = (L + R) >> 1;
     87         int lc = lch(o), rc = rch(o);
     88         if(qR <= M) return query(lc, L, M);
     89         if(qL > M) return query(rc, M+1, R);
     90         Interval i1 = query_suffix(lc, L, M);//左子区间的最大后缀
     91         Interval i2 = query_prefix(rc, M+1, R);//右子区间的最大前缀
     92         Interval i3 = better(query(lc, L, M), query(rc, M+1, R));//两个子区间的最大连续和
     93         return better(i3, MP(i1.first, i2.second));
     94     }
     95 }tree;
     96 
     97 int main()
     98 {
     99     //freopen("in.txt", "r", stdin);
    100 
    101     int kase = 0, n, a, Q;
    102     while(scanf("%d%d", &n, &Q) == 2)
    103     {
    104         prefix_sum[0] = 0;
    105         for(int i = 1; i <= n; i++) { scanf("%d", &a); prefix_sum[i] = prefix_sum[i-1] + a; }
    106         tree.build(1, 1, n);
    107         printf("Case %d:
    ", ++kase);
    108         while(Q--)
    109         {
    110             int L, R;
    111             scanf("%d%d", &L, &R);
    112             qL = L; qR = R;
    113             Interval ans = tree.query(1, 1, n);
    114             printf("%d %d
    ", ans.first, ans.second);
    115         }
    116     }
    117 
    118     return 0;
    119 }
    代码君
  • 相关阅读:
    Kali Linux下安装配置ProFTPD实例
    mysql 如何用root 登录
    串口总是报'Error opening serial port'
    用SPCOMM 在 Delphi中实现串口通讯 转
    delphi中使用spcomm来实现串口通讯(转载)
    SPCOMM的一些用法注意
    MySQL 字符串 转 int/double CAST与CONVERT 函数的用法
    彻底删除mysql服务
    mysql 非安装版的一个自动安装脚本及工具(更新版)
    bat操作数据库mysql
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4356495.html
Copyright © 2020-2023  润新知