vijos P1083小白逛公园

描述

小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。

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

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

格式

输入格式

第一行,两个整数N和M,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。

接下来N行,每行一个整数,依次给出小白 开始时对公园的打分。

接下来M行,每行三个整数。第一个整数K,1或2。K=1表示,小新要带小白出去玩,接下来的两个整数a和b给出了选择公园的范围(1≤a,b≤N, a可以大于b!);K=2表示,小白改变了对某个公园的打分,接下来的两个整数p和s,表示小白对第p个公园的打分变成了s(1≤p≤N)。

其中,1≤N≤500 000,1≤M≤100 000,所有打分都是绝对值不超过1000的整数。

输出格式

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

样例1

样例输入1

5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 2 3

样例输出1

2
-1

 

首先对于询问,我们知道有O(n)的算法,但是在这里肯定是不行的。。。

然后我们对于区间上的问题应该想到线段树。。。

我们对于线段树可以增加三个状态:lmax,rmax,mx;表示这个区间从左端点/右端点开始的最大连续子序列,mx表示总的最大连续子序列;

然后易得,对于f[i]:

f[i].lmax=max(f[i*2].lmax,f[i*2].sum+f[i*2+1].lmax);
f[i].rmax=max(f[i*2+1].rmax,f[i*2+1].sum+f[i*2].rmax);
f[i].mx=max(f[i*2].mx,max(f[i*2+1].mx,f[i*2].rmax+f[i*2+1].lmax));

然后再加上单点修改即可。。。

对于query。。。很多人返回的是节点。。。但是也可以返回值,只不过要麻烦一点,

int qleft(int right ,int i){
	while(f[i].r>right)i*=2;
	if(f[i].r==right)return f[i].lmax;
	else return max(f[i].lmax, qleft(right,i+1)+f[i].sum);
}
int qright(int left, int i){
	while(f[i].l<left)i=i*2+1;
	if(f[i].l==left)return f[i].rmax;
	else return max(f[i].rmax, qright(left,i-1)+f[i].sum);
} 

int query(int i,int left,int right) {
        int mid=(f[i].l+f[i].r)/2;
        if(f[i].l==left&&f[i].r==right) return f[i].mx;
        if(mid>=right) return query(i*2,left,right);
        if(mid<left) return query(i*2+1,left,right);
        else{
			int tmp=max(query(i*2,left,mid),query(i*2+1,mid+1,right));
			return max(tmp,qleft(right,i*2+1)+qright(left,i*2));
		}
}

这样就好了。。。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #define maxn 500010
 7 #define maxm 100000
 8 #define inf 100000000
 9 using namespace std;
10 int a[maxn];
11 struct tree{
12     int l,r,sum,mx,lmax,rmax;
13 }f[maxn*4];
14  
15 void pushup(int i){
16     f[i].sum=(f[i*2+1].sum+f[i*2].sum);
17     f[i].lmax=max(f[i*2].lmax,f[i*2].sum+f[i*2+1].lmax);
18     f[i].rmax=max(f[i*2+1].rmax,f[i*2+1].sum+f[i*2].rmax);
19     f[i].mx=max(f[i*2].mx,max(f[i*2+1].mx,f[i*2].rmax+f[i*2+1].lmax));
20 }
21 
22 void update(int i,int x)
23 {
24     f[i].sum=f[i].lmax=f[i].rmax=f[i].mx=x;
25     return;
26 }
27 
28 void build(int i,int left,int right){
29     int mid=(left+right)/2;
30     f[i].l=left;f[i].r=right;
31     if(left==right){
32         f[i].sum=f[i].lmax=f[i].rmax=f[i].mx=a[left];
33         return;
34     }
35     build(i*2,left,mid);
36     build(i*2+1,mid+1,right);
37     pushup(i);
38 }
39  
40 void change(int i,int left,int right,int v){
41     int mid=(f[i].l+f[i].r)/2;
42     if(f[i].l==left&&f[i].r==right){
43         update(i,v);
44         return;
45     }
46     if(mid>=right)change(i*2,left,right,v);  
47     else if(mid<left)change(i*2+1,left,right,v);
48     pushup(i);
49 }
50 
51 int qleft(int right ,int i){
52     while(f[i].r>right)i*=2;
53     if(f[i].r==right)return f[i].lmax;
54     else return max(f[i].lmax, qleft(right,i+1)+f[i].sum);
55 }
56 int qright(int left, int i){
57     while(f[i].l<left)i=i*2+1;
58     if(f[i].l==left)return f[i].rmax;
59     else return max(f[i].rmax, qright(left,i-1)+f[i].sum);
60 } 
61 
62 int query(int i,int left,int right) {
63         int mid=(f[i].l+f[i].r)/2;
64         if(f[i].l==left&&f[i].r==right) return f[i].mx;
65         if(mid>=right) return query(i*2,left,right);
66         if(mid<left) return query(i*2+1,left,right);
67         else{
68             int tmp=max(query(i*2,left,mid),query(i*2+1,mid+1,right));
69             return max(tmp,qleft(right,i*2+1)+qright(left,i*2));
70         }
71 }
72 
73 int main(){
74     int n,m;
75     scanf("%d%d",&n,&m);
76     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
77     build(1,1,n);
78     for(int i=1;i<=m;i++){
79         int x,y,z;
80         scanf("%d",&x);
81         if(x==1){
82             scanf("%d%d",&y,&z);
83             printf("%d\n",query(1,min(z,y),max(z,y)));
84         }
85         if(x==2){
86             scanf("%d%d",&y,&z);
87             change(1,y,y,z);
88         }
89     }
90     return 0;
91 }
View Code

 

 

转载于:https://www.cnblogs.com/htwx/articles/4907328.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值