zoukankan      html  css  js  c++  java
  • [SGT] 线段树维护区间最大子段和

    蓝书P208

    https://vjudge.net/problem/SPOJ-GSS1


    若将一区间分为两部分,则必有最大子段存在于左区间 / 右区间 / 跨越中间

    因此当前节点记录该段的最大前缀和,最大后缀和,段和,区间内最大子段和

    	now.sum = ls.sum + rs.sum;
    	now.lmax = max(ls.lmax, ls.sum + rs.lmax);
    	now.rmax = max(rs.rmax, rs.sum + ls.rmax);
    	now.val = max(ls.val, max( rs.val, ls.rmax + rs.lmax) );

    修改,建树时直接按定义push

    查询相当于建颗查询区间内的子树再暴力合并至根节点返回

    代码

    /*
        Zeolim - An AC a day keeps the bug away
    */
     
    //pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    
    #define mp(x, y) make_pair(x, y)
    #define fr(x, z, y) for(int x = z; x < y; ++x)
    
    typedef long long ll;
    typedef double ld;
    typedef std::pair<int, int> pii;
    typedef std::vector <short> vi;
    //typedef __int128 ill;
    
    const ld PI = acos(-1.0);
    const ld E = exp(1.0);
    const ll INF = 1e18;
    const ll MOD = 1e9 + 7;
    const int MAXN = 1e6 + 100;
    
    int n, m;
    
    struct node
    {
    	int l, r;
    	int val;
    	int sum, lmax, rmax;
    }tr[MAXN * 4];
    
    int arr[MAXN] = {0};
    
    void push(node &now, node &ls, node &rs)
    {
    	now.sum = ls.sum + rs.sum;
    	now.lmax = max(ls.lmax, ls.sum + rs.lmax);
    	now.rmax = max(rs.rmax, rs.sum + ls.rmax);
    	now.val = max(ls.val, max( rs.val, ls.rmax + rs.lmax) );
    }
    
    void build(int now, int l, int r)
    {
    	tr[now].l = l, tr[now].r = r;
    	int mid = (l + r) / 2;
    	if(l == r) {tr[now].val = tr[now].sum = tr[now].lmax = tr[now].rmax = arr[l]; return;}
    	build(now * 2, l, mid);
    	build(now * 2 + 1, mid + 1, r);
    	push(tr[now], tr[now * 2], tr[now * 2 + 1]);
    }
    
    void change(int now, int p, int v)
    {
    	if(tr[now].l == tr[now].r) { tr[now].val = tr[now].sum = tr[now].lmax = tr[now].rmax = v; return;}
    	int mid = (tr[now].l + tr[now].r) / 2;
    	if(p <= mid) change(now * 2, p, v);
    	if(p > mid) change(now * 2 + 1, p, v);
    	push(tr[now], tr[now * 2], tr[now * 2 + 1]);
    }
    
    node ask(int now, int l, int r)
    {
    	if(l <= tr[now].l && r >= tr[now].r) return tr[now];
    	int mid = (tr[now].l + tr[now].r) / 2;
    	if(r <= mid) return ask(now * 2, l, r);
    	if(l > mid) return ask(now * 2 + 1, l, r);
    	node ls = ask(now * 2, l, r), rs = ask(now * 2 + 1, l, r), ans;
    	push(ans, ls, rs);
    	return ans;
    }
    
    
    int main()
    {  
        ios::sync_with_stdio(0);
        cin.tie(0); cout.tie(0);
        //freopen("d:out.txt","w",stdout);
      	//freopen("d:in.txt","r",stdin);
      	cin >> n;
      	fr(i, 1, n + 1)
      		cin >> arr[i];
      	build(1, 1, n);
      	cin >> m;
      	int op, x, y;
      	fr(i, 0, m)
      	{
      		cin  >> x >> y;
      		cout << ask(1, x, y).val << '
    ';
      	}
        return 0;
    }
  • 相关阅读:
    7月15日考试 题解(链表+状压DP+思维题)
    暑假集训日记
    C# .NET 使用 NPOI 生成 .xlsx 格式 Excel
    JavaSE 基础 第42节 局部内部类
    JavaSE 基础 第41节 匿名内部类
    JavaSE 基础 第40节 内部类概述
    JavaSE 基础 第39节 接口的应用
    JavaSE 基础 第38节 接口的实现
    JavaSE 基础 第37节 接口概述
    JavaSE 基础 第36节 抽象类概述与使用
  • 原文地址:https://www.cnblogs.com/zeolim/p/12270352.html
Copyright © 2011-2022 走看看