描述
小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着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));
}
}
这样就好了。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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 }