SP1716 GSS3 - Can you answer these queries III 线段树(结构体模板)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sdz20172133/article/details/83834684

题意翻译

nn 个数,qq 次操作

操作0 x y把A_xAx​ 修改为yy

操作1 l r询问区间[l, r][l,r] 的最大子段和

感谢 @Edgration 提供的翻译

题目描述

You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations:
modify the i-th element in the sequence or for given x y print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.

输入输出格式

输入格式:

The first line of input contains an integer N. The following line contains N integers, representing the sequence A1..AN.
The third line contains an integer M. The next M lines contain the operations in following form:
0 x y: modify Ax into y (|y|<=10000).
1 x y: print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.

输出格式:

扫描二维码关注公众号,回复: 4121016 查看本文章

For each query, print an integer as the problem required.

输入输出样例

输入样例#1: 复制

4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3

输出样例#1: 复制

6
4
-3

分析:

见这篇博客

https://blog.csdn.net/SSL_ZYC/article/details/81951129

数组线段树模板:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
using namespace std;
const double eps = 1e-8;
typedef long long LL;
#define lson i<<1, l, m      /// i*2
#define rson i<<1|1, m+1, r  /// i*2+1
const int maxn=500000+5;
//线段树需要维护的信息
int sum[maxn*4]; //四倍
int lmaxn[maxn*4],rmaxn[maxn*4],dat[maxn*4];
int a[maxn],ans,pre;
///区间和sumsum,区间最大连续字段和datdat,
///紧靠左端的最大连续字段和lmaxlmax,紧靠右端的最大连续字段和rmaxrmax

 
//i节点收集子节点的统计结果
void PushUp(int i) //求和
{
    sum[i]=sum[i<<1]+sum[i<<1|1];
    lmaxn[i]=max(lmaxn[i<<1],  sum[i<<1]+lmaxn[i<<1|1]);
    rmaxn[i]=max(rmaxn[i<<1|1],sum[i<<1|1]+rmaxn[i<<1]);
    dat[i]=max(max(dat[i<<1],  dat[i<<1|1]),lmaxn[i<<1|1]+rmaxn[i<<1]);
}
 
//递归建立线段树
void build(int i,int l,int r)
{
    if(l==r)
    {
    	sum[i]=a[l];
    	lmaxn[i]=a[l];
        rmaxn[i]=a[l];
        dat[i]=a[l];
        return ;
    }
 
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(i);//收集子节点的结果
}
 
//在当前区间[l, r]内查询区间[ql, qr]间的目标值
//且能执行这个函数的前提是:[l,r]与[ql,qr]的交集非空
//其实本函数返回的结果也是 它们交集的目标值
void query(int ql,int qr,int i,int l,int r)
{
    //目的区间包含当前区间
    if(ql<=l && r<=qr) 
    {
        ans=max(ans,dat[i]);//计算
        ans=max(ans,pre+lmaxn[i]);
        pre=max(rmaxn[i],pre+sum[i]);//维护pre
        return ;
    }
    
    int m=(l+r)>>1;
    int res=0;
    if(ql<=m) query(ql,qr,lson);
    if(m<qr)  query(ql,qr,rson);
}
//本题是单点更新,所以是在区间[l,r]内使得第id数的值+val
//如果是区间更新,可以update的参数需要将id变为ql和qr
void update(int id,int val,int i,int l,int r)
{
    if(l==r)
    {
        sum[i] = val;
        lmaxn[i]=val;
        rmaxn[i]=val;
        dat[i]=val;
        return ;
    }
 
    int m=(l+r)>>1;
    if(id<=m) update(id,val,lson);
    else update(id,val,rson);
    PushUp(i);//时刻记住维护i节点统计信息正确性
}
int main()
{
    int n;//节点总数
    while(scanf("%d",&n)!=-1)
    {
      
        for(int i=1;i<=n;i++)
        	scanf("%d",&a[i]);
        build(1,1,n);//建立线段树

        int b,u,v;
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d%d",&b,&u,&v);
            if(b==1) 
            {
                ans=-1e9;pre=-1e9;
                if(u>v) swap(u,v);
                
                query(u,v,1,1,n);
                printf("%d\n",ans);
            }
            else if(b==0) update(u,v,1,1,n);
        }
    }
    return 0;
}

结构体线段树代码:

#include <cstdio>
#include <algorithm>
#define N 500010
using namespace std;

int a[N];
int n,m,w,x,y,z;

struct node  //线段树
{
    int l,r,sum,max,lmax,rmax;
}tree[N*4];

int maxx(int x,int y,int z)
{
    return max(x,max(y,z));
}
void PushUp(int x) 
{
     tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
    tree[x].lmax=max(tree[x*2].lmax,tree[x*2].sum+tree[x*2+1].lmax);
    tree[x].rmax=max(tree[x*2+1].rmax,tree[x*2+1].sum+tree[x*2].rmax);
    tree[x].max=maxx(tree[x*2].max,tree[x*2+1].max,tree[x*2].rmax+tree[x*2+1].lmax);  //求出每个点的所有值
}
void make(int x)  //建树
{
    if (tree[x].l==tree[x].r)   //叶子节点
    {
        tree[x].sum=a[tree[x].l];
        tree[x].lmax=a[tree[x].l];
        tree[x].rmax=a[tree[x].l];
        tree[x].max=a[tree[x].l];  //只有一个可能,它本身
        return;
    }
    int mid=(tree[x].l+tree[x].r)/2;
    tree[x*2].l=tree[x].l;
    tree[x*2].r=mid;
    tree[x*2+1].l=mid+1;
    tree[x*2+1].r=tree[x].r;  //左右儿子的边界
    make(x*2);
    make(x*2+1);
	PushUp(x);
}  

node find(int x,int l,int r)  //查找
{  
    if (tree[x].l==l&&tree[x].r==r) return tree[x];  //找到
    if (tree[x].l==tree[x].r) return (node){0,0,0,0,0,0};  //不成立
    int mid=(tree[x].l+tree[x].r)/2;
    if (r<=mid) return (node)find(x*2,l,r);
    if (l>mid) return (node)find(x*2+1,l,r); 
    
    node a=find(x*2,l,mid),b=find(x*2+1,mid+1,r),c;
    c.sum=a.sum+b.sum;
    c.lmax=max(a.lmax,a.sum+b.lmax);
    c.rmax=max(b.rmax,b.sum+a.rmax);
    c.max=maxx(a.max,b.max,a.rmax+b.lmax);  //求答案
    return c;
}

void add(int x,int y,int k)  //修改
{
    if (tree[x].l==y&&tree[x].r==y)  //找到
    {
        tree[x].sum=k;
        tree[x].lmax=k;
        tree[x].rmax=k;
        tree[x].max=k;  //重新更新
        return;
    }
    if (tree[x].l==tree[x].r) return;
    int mid=(tree[x].l+tree[x].r)/2;
    if (y<=mid)
    {
        add(x*2,y,k);
        
    }
    else
    {
        add(x*2+1,y,k);
    }
     PushUp(x);
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
     scanf("%d",&a[i]);
    tree[1].l=1;
    tree[1].r=n;
    make(1);    
    scanf("%d",&m);
    while (m--)
    {
        scanf("%d%d%d",&z,&x,&y);
        if (z)
        {
            if (x>y) swap(x,y);
            find(1,x,y);            
            printf("%d\n",find(1,x,y).max);
        }
        else
        {
            add(1,x,y);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdz20172133/article/details/83834684