您的位置:首页 > 其它

小白逛公园——————我很弱,题解写的不好请指出;

2015-06-19 13:47 405 查看
小白逛公园
Time Limit:20000MS Memory Limit:65536K

Total Submit:107 Accepted:48

Case Time Limit:2000MS
Description

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

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

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

Input

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

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

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

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

Output

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

Sample Input


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


Sample Output


2
-1

#include<cstdio>
#define inf 999999999
#define maxn 1000005
int L[maxn],R[maxn],ls[maxn],rs[maxn],maxx[maxn];
//L[i]表示从区间左边数,得到的最大值;
//R[i]表示从区间右边数,得到的最大值;
//ls[i]左儿子,rs[i]右儿子;
//a[i]左边界,b[i]右边界;
//maxx[i]最大值,sum[i]区间和;
int a[maxn],b[maxn],sum[maxn],tot,qq,pp;
void _r(int& d)//输入优化;
{
char t=getchar();bool f=false;
while(t<'0'||t>'9') {if(t=='-') f=true; t=getchar();}
for(d=0;t<='9'&&t>='0';t=getchar()) d=d*10+t-'0';
if(f) d=-d;
}
void _w(int d)//输出优化;
{
int o[30],top=1;
if(d==0){putchar('0');return ;}
if(d<0) {putchar('-');d=-d;}
while(d)
{
o[top++]=d%10;
d/=10;
}
for(--top;top;--top) putchar('0'+o[top]);
}
int _max(int x,int y)
{
if(x>y)return x;
else return y;
}
void work(int i)
{
sum[i]=sum[ls[i]]+sum[rs[i]];//求和;
L[i]=_max(L[ls[i]],sum[ls[i]]+L[rs[i]]);//当前从左数L[i]最大值为max(左儿子L[i],左边和+右儿子L[i]);
R[i]=_max(R[rs[i]],sum[rs[i]]+R[ls[i]]);//同理,求得当前从右数R[i]最大值;
maxx[i]=_max(_max(maxx[ls[i]],maxx[rs[i]]),L[rs[i]]+R[ls[i]]);
//更新当前区间最大值;
//1.左儿子最大值;
//2.右儿子最大值;
//3.右儿子左边最大+左儿子右边最大;
//PS:相当于分别在左,中,右找得最大值;
}
void make(int l,int r)//建树
{
int i=++tot;
a[i]=l,b[i]=r;
if(l<r)
{
ls[i]=tot+1,make(l,(l+r)/2);
rs[i]=tot+1,make((l+r)/2+1,r);
work(i);//每次更新当前区间的L[i],sum[i],maxx[i],R[i];
}
else
{
_r(maxx[i]);
sum[i]=L[i]=R[i]=maxx[i];
}
}
int find_l(int i)//找右儿子的左边;
{
//将当前区间分为两半;
//它的L[i]最大值,要么是左儿子L[i],要么是左边和+右儿子L[i];
int t=-inf;
if(b[i]<=qq)return L[i];//当前区间包含在pp-qq中;
if(ls[i])t=_max(t,find_l(ls[i]));/
if(rs[i]&&a[rs[i]]<=qq)t=_max(t,sum[ls[i]]+find_l(rs[i]));
return t;
}
int find_r(int i)//找左儿子的右边;
{
//同找左儿子一样;
int t=-inf;
if(pp<=a[i])return R[i];//当前区间包含在pp-qq中;
if(rs[i])t=_max(t,find_r(rs[i]));
if(ls[i]&&pp<=b[ls[i]])t=_max(t,sum[rs[i]]+find_r(ls[i]));//当前区间依旧与pp-qq相交;
return t;
}
int find_ans(int i)
{
int t=-inf;
if(pp<=a[i]&&b[i]<=qq)return maxx[i];//如果包含在pp-qq间,返回值;
if(ls[i]&&pp<=b[ls[i]])t=_max(t,find_ans(ls[i]));//查找左儿子;
if(rs[i]&&a[rs[i]]<=qq)t=_max(t,find_ans(rs[i]));//查找右儿子;
if(ls[i]&&rs[i]&&pp<=b[ls[i]]&&a[rs[i]]<=qq)//查找左儿子的右边和右儿子的左边;
t=_max(t,find_l(rs[i])+find_r(ls[i]));
return t;//分三次找左,中,右;取得最大;
}
void change(int i)
{
if(a[i]==b[i])
{
sum[i]=maxx[i]=L[i]=R[i]=qq;//更新i节点;
return;
}
if(ls[i]&&pp<=b[ls[i]])change(ls[i]);//查找左儿子;
if(rs[i]&&a[rs[i]]<=pp)change(rs[i]);//查找右儿子;
work(i);// 更新包含i的区间;
}
int main()
{
int n,m,i,k,t;
_r(n),_r(m);
make(1,n);
for(i=1;i<=m;i++)
{
_r(k),_r(pp),_r(qq);
if(k==1)
{
if(pp>qq){t=pp;pp=qq;qq=t;}//按顺序读入区间[pp,qq];
_w(find_ans(1)),putchar(10);
}
else change(1);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: