/*少说话,多做事*/ #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <vector> #include <stack> #include <sstream> #include <map> #include <set> #include <queue> #include <stdlib.h> using namespace std; #define ll long long #define inf 0x3f3f3f3f const int SIZE=500005; int a[SIZE]; struct segment { int l,r; int ls,rs;//l最大前缀和 \ r最大后缀和 int sum,dat; //sum为区间和,dat为最后的结果 }t[2000005]; void update(int p) { int zuo = p<<1; int you = p<<1|1; /*更新p点的区间和 、最大前缀和 、最大后缀和 、最终的结果*/ t[p].sum = t[you].sum + t[zuo].sum; //p点的sum值为两个子节点之和 t[p].ls = max(t[zuo].ls , t[zuo].sum + t[you].ls); //p点的最大前缀和是 max(左面的最大前缀和 , 右面的最大前缀和 + 左面的区间和) t[p].rs = max(t[you].rs , t[zuo].rs + t[you].sum); //p点的最大后缀和是 max(右面的最大后缀和 ,左面的最大后缀和 + 右面的区间和) t[p].dat = max(t[zuo].dat , max(t[you].dat , t[zuo].rs+t[you].ls)); //左面的dat,右面的dat,以及左面的后缀加右面的前缀 } void build(int p,int l,int r) //建树:当前节点编号,范围,[l,r] { t[p].l=l; //当前节点的编号是l, t[p].r=r; //当前节点的编号是r, if(l==r) //如果l==r,那么说明到了最底层 { t[p].dat = t[p].ls = t[p].rs = t[p].sum = a[l]; return; } /*左右递归*/ int mid=(l+r)>>1; //中间的数是,两者相加/2 build(p<<1,l,mid); //左面递归 /* p*2是偶数,然后跟1按位或,就是+1的意思,总的意思是:p*2+1 */ build(p<<1|1,mid+1,r); //右面递归 update(p); //更新p点的值 } void change(int p,int x,int v) { if(t[p].l==t[p].r){ t[p].dat=t[p].ls=t[p].rs=t[p].sum=v; return ; } int mid=(t[p].l+t[p].r)>>1; if(x<=mid) change(p<<1,x,v); else change(p<<1|1,x,v); update(p); } segment query(int p,int l,int r) //1 L~R区间的最大连续子段和 (从最开始的一号往下找) { if(l<=t[p].l && r>=t[p].r) //如果L比p的l小,且R比p的r大,即:p所能确定的范围在l和r之间 { return t[p]; //将p这个节点返回就好了 } int mid = (t[p].l+t[p].r)>>1; //求出p点区间中心值 segment nod,nod1,nod2; int f=0; if(l<=mid) //如果查询的l在中心值的左面 { nod1=query(p<<1,l,r); f+=1; } if(r>mid) //如果查询的r在中心值的右面 { nod2=query(p<<1|1,l,r); f+=2; } if(f==3) //那么两边一定都被遍历过 { nod.sum = nod1.sum+nod2.sum; //如果l和r在mid的两遍,返回节点的sum值=两个节点区间之和 nod.ls=max(nod1.ls,nod1.sum+nod2.ls); nod.rs=max(nod2.rs,nod2.sum+nod1.rs); nod.dat=max(nod1.dat,max(nod2.dat,nod1.rs+nod2.ls)); } if(f==1) nod = nod1; //如果f==1,则表明只进行第一个if语句, if(f==2) nod = nod2; return nod; } int main() { for (int i=1;i<=10;i++) //第二种输入方法 { cin >> a[i]; } int N,M; cin >> N >> M; //n是区间的大小,m次询问 for(int i=1;i<=N;i++) { cin >> a[i]; } build(1,1,N); // 1 1 N 当前节点编号,左面的,右面的 int k,x,y; while(M--) { cin >> k >> x >> y; if(k==1) //查询 { if(x>y) swap(x,y); //将x和y从小到大排序 cout << query(1,x,y).dat << endl; //dat是x,y中最大连续子段和 } else change(1,x,y); //将a[x]变为y } return 0; }