小白逛公园

来源:互联网 发布:车辆调度算法研究 编辑:程序博客网 时间:2024/06/02 19:46

小白逛公园

Time Limit:20000MS  Memory Limit:65536K
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 31 2 -3 4 51 2 32 2 -11 2 3

Sample Output

2-1

Source

vijos



#include <stdio.h>#define maxn 500000#define inf -2100000000inline void _read(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;}inline void _out(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]);}struct node{int a, b, l, r, lmax, rmax, max, sum;}tree[maxn*2+9];int mark[maxn+9], tot=0;int rofmax2(int a, int b){if(a>b)return a;return b;}int rofmax3(int a, int b, int c){return rofmax2(rofmax2(a, b), c);}int Min(int a, int b){if(a<b)return a;return b;}void updata(int now){//以下全部维护当前区间的数据 int ls=tree[now].l, rs=tree[now].r;tree[now].sum=tree[ls].sum+tree[rs].sum;//维护区间和 tree[now].lmax=rofmax2(tree[ls].lmax, tree[ls].sum+tree[rs].lmax);//维护左起最长连续和 tree[now].rmax=rofmax2(tree[rs].rmax, tree[rs].sum+tree[ls].rmax);//维护右起最长连续和 tree[now].max=rofmax3(tree[ls].max, tree[rs].max, tree[ls].rmax+tree[rs].lmax);//维护最长区间和 }void maketree(int x, int y){int now=++tot;tree[now].a=x;tree[now].b=y;tree[now].lmax=tree[now].rmax=tree[now].max=tree[now].sum=inf;if(x==y){tree[now].l=0;tree[now].r=0;tree[now].max=tree[now].lmax=tree[now].rmax=tree[now].sum=mark[x];return;}tree[now].l=tot+1;maketree(x, (x+y)/2);tree[now].r=tot+1;maketree((x+y)/2+1, y);updata(now); }int _search_right(int i, int l, int r){    int t=-2100000000;    if(l<=tree[i].a)return tree[i].rmax;if(tree[i].r)t=rofmax2(t, _search_right(tree[i].r, l, r));   if(tree[i].l&&l<=tree[tree[i].l].b)t=rofmax2(t,tree[tree[i].r].sum+_search_right(tree[i].l, l, r));    return t;}int _search_left(int i, int l, int r){    int t=-2100000000;    if(r>=tree[i].b)returntree[i].lmax;//如果当前节点包含于[l, r], 返回当前节点的左起最大连续和     if(tree[i].l)t=rofmax2(t, _search_left(tree[i].l, l, r));if(tree[i].r&&r>=tree[tree[i].r].a)t=rofmax2(t, tree[tree[i].l].sum+_search_left(tree[i].r, l, r));    return t;}int getans(int p, int l, int r){if(l<=tree[p].a&&tree[p].b<=r)return tree[p].max;//如果当前节点包含于[l, r], 返回当前节点的最长连续和 int mid=(tree[p].a+tree[p].b)/2, lmax=inf, rmax=inf; if(l<=mid)lmax=getans(tree[p].l, l, r);//左儿子与[l, r]区间相交部分的最长连续和 if(r>mid)rmax=getans(tree[p].r, l, r);//有儿子与[l, r]区间相交部分的最长连续和 int lt=tree[p].l, rt=tree[p].r;int lenm=-2100000000;if(l<=tree[lt].b&&tree[rt].a<=r)//如果左右儿子都与[l, r]相交, {lenm=_search_left(rt, l, r)//固定左边界向右搜索最大连续和 +_search_right(lt, l, r);//固定右边界向左搜索最大连续和 }return rofmax2(lmax, rofmax2(rmax, lenm));}void change(int now, int k, int s)//第k个公园的分数变为s,当前讨论到 now 点 {if(tree[now].a<=k&&k<=tree[now].b)//如果第k个公园在当前节点表示的区间之内 {if(tree[now].a==tree[now].b)//如果当前节点是叶节点 {tree[now].lmax=tree[now].rmax=tree[now].max=tree[now].sum=s;}else//如果当前节点不是叶节点 {change(tree[now].l, k, s);change(tree[now].r, k, s);updata(now);}}}int main(){int n, m, alt, a, b, p, s;_read(n);_read(m);//n个公园,m个操作 for(int i=1; i<=n; i++)//读入每个公园的分数 {_read(mark[i]); }maketree(1, n);//建树 for(int i=1; i<=m; i++){_read(alt);if(1==alt){_read(a);_read(b);//选择公园的范围[a, b] if(a>b)//有可能a>b, 交换a,b {int t=a;a=b;b=t;}_out(getans(1, a, b));//输出[a, b]最长连续和 putchar('\n');}else{_read(p);_read(s);change(1, p, s);//第p个公园的分变成s }}return 0;}


0 0
原创粉丝点击