洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间合并(单点更新、区间查询)...

P4513 小白逛公园

题目背景

小新经常陪小白去公园玩,也就是所谓的遛狗啦…

题目描述

在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。

一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第aa个和第bb个公园之间(包括aa、bb两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。

那么,就请你来帮小白选择公园吧。

输入输出格式

输入格式:

 

第一行,两个整数NN和MM,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来NN行,每行一个整数,依次给出小白 开始时对公园的打分。
接下来MM行,每行三个整数。第一个整数KK,11或22。

  • K=1K=1表示,小新要带小白出去玩,接下来的两个整数aa和bb给出了选择公园的范围(1≤a,b≤N1a,bN)。测试数据可能会出现a>ba>b的情况,需要进行交换;
  • K=2K=2表示,小白改变了对某个公园的打分,接下来的两个整数pp和ss,表示小白对第pp个公园的打分变成了ss(1≤p≤N1pN)。
    其中,1≤N≤500 0001N500000,1≤M≤100 0001M100000,所有打分都是绝对值不超过10001000的整数。

 

输出格式:

 

小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。

 

输入输出样例

输入样例#1:  复制
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 2 3
输出样例#1:  复制
2
-1

 

 

区间最大子段和,正常的区间不变的可以分治或者dp啥的,线段树的就维护最大前缀和,最大后缀和,之类的。

具体的代码写了注释。。。

 

代码:

 1 //线段树-分治+区间合并
 2 //区间最大子段和有三种情况:
 3 //1.左子树最大子段和
 4 //2.右子树最大子段和
 5 //3.左子树的最大后缀和+右子树的最大前缀和
 6 
 7 //思路特别简单,但是写自己顺手的模板改的时间有点久,最后选择了这种方式,其他int返回值的函数有代码重复的操作
 8 
 9 #include<bits/stdc++.h>
10 using namespace std;
11 typedef long long ll;
12 const int maxn=5e5+10;
13 
14 #define lson l,m,rt<<1
15 #define rson m+1,r,rt<<1|1
16 
17 struct Tree{
18     int pre,suf,sub,val;//pre为当前区间最大前缀和,suf为当前区间最大后缀和,sub为当前区间最大子段和,val为当前区间的和
19 }tree[maxn<<2];
20 
21 Tree pushup(Tree l,Tree r)
22 {
23     Tree rt;
24     rt.pre=max(l.pre,l.val+r.pre);//当前区间的最大前缀和:左子树的最大前缀和 or 左子树的和+右子树的最大前缀和
25     rt.suf=max(r.suf,r.val+l.suf);//当前区间的最大后缀和:右子树的最大后缀和 or 右子树的和+左子树的最大后缀和
26     rt.sub=max(max(l.sub,r.sub),l.suf+r.pre);//当前区间的最大子段和:左子树的最大子段和 or 右子树的最大子段和 or 左子树的最大后缀和+右子树的最大前缀和
27     rt.val=l.val+r.val;//当前区间的和:左子树的和+右子树的和
28     return rt;
29 }
30 
31 void build(int l,int r,int rt)
32 {
33     if(l==r){
34         scanf("%d",&tree[rt].val);
35         tree[rt].pre=tree[rt].suf=tree[rt].sub=tree[rt].val;
36         return ;
37     }
38 
39     int m=(l+r)>>1;
40     build(lson);
41     build(rson);
42     tree[rt]=pushup(tree[rt<<1],tree[rt<<1|1]);
43 }
44 
45 void update(int pos,int c,int l,int r,int rt)
46 {
47     if(l==r){
48         tree[rt].pre=tree[rt].suf=tree[rt].sub=tree[rt].val=c;
49         return ;
50     }
51 
52     int m=(l+r)>>1;
53     if(pos<=m) update(pos,c,lson);
54     if(pos> m) update(pos,c,rson);
55     tree[rt]=pushup(tree[rt<<1],tree[rt<<1|1]);
56 }
57 
58 Tree query(int L,int R,int l,int r,int rt)
59 {
60     if(L<=l&&r<=R){
61         return tree[rt];
62     }
63 
64     int m=(l+r)>>1;
65     Tree ret,lret,rret;
66     int flag1=0,flag2=0;
67     if(L<=m) {lret=query(L,R,lson);flag1=1;}
68     if(R> m) {rret=query(L,R,rson);flag2=1;}
69 
70     if(flag1&&flag2) ret=pushup(lret,rret);//合并
71     else if(flag1) ret=lret;
72     else if(flag2) ret=rret;
73     return ret;
74 }
75 
76 int main()
77 {
78     int n,m;
79     scanf("%d%d",&n,&m);
80     build(1,n,1);
81     for(int i=1;i<=m;i++){
82         int op;
83         scanf("%d",&op);
84         if(op==1){
85             int l,r;
86             scanf("%d%d",&l,&r);
87             if(l>r) swap(l,r);
88             Tree ans=query(l,r,1,n,1);
89             printf("%d\n",ans.sub);
90         }
91         else{
92             int p,s;
93             scanf("%d%d",&p,&s);
94             update(p,s,1,n,1);
95         }
96     }
97     return 0;
98 }

 

转载于:https://www.cnblogs.com/ZERO-/p/10679858.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值