1. 程式人生 > 其它 >nlfsoj 20035 #10851 最大連續子段和 SP1716 GSS3 - Can you answer these queries III

nlfsoj 20035 #10851 最大連續子段和 SP1716 GSS3 - Can you answer these queries III

\(n\) 個數,\(q\) 個操作

操作 \(0\ x\ y\) 表示把 \(a_x\) 修改為 \(y\)

操作 \(1\ l\ r\) 詢問 \([l,r]\) 的最大子段和

\(1\leq n,q\leq 50000,|y|\leq 10000\)

sol1

線段樹做法 .

每個節點維護,字首最大值 \(a\),字尾最大值 \(b\),區間內最大連續子段和 \(c\) , 區間和 \(w\) .

只有單點查詢,所以只需要考慮合併操作 .

將左區間 \(l\) 和右區間 \(r\) 合併到 \(x\) .

\(x.a=\max(l.a,l.w+r.a)\) 字首最大值在左區間 \(l.a\) ,在右區間 \(l.w+r.a\)

\(x.b=\max(r.b,r.w+l.b)\) 字尾最大值在右區間 \(r.b\) ,在左區間 \(r.w+l.b\)

\(x.c=\max(l.c,r.c,l.b+r.a)\)

區間最大連續子段和在左區間 \(l.c\),在右區間 \(r.c\),兩個區間都有,即 \(l.b+r.a\)

\(x.w=l.w+r.w\)

知道了合併操作,區間求和,單點修改就都不在話下了 .

時間複雜度 : \(\mathrm O(q\log n)\)

空間複雜度 : \(\mathrm O(n)\)

code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	while((ch<'0'||ch>'9')&&(ch!='-'))ch=getchar();
	int f=false;
	if(ch=='-'){
		f=true;
		ch=getchar();
	}
	int res=0;
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	if(f)res=-res;
	return res;
}
inline void print(int res){
	if(res==0){
		putchar('0');
		return;
	}
	if(res<0){
		putchar('-');
		res=-res;
	}
	int a[10],len=0;
	while(res>0){
		a[len++]=res%10;
		res/=10;
	}
	for(int i=len-1;i>=0;i--)
		putchar(a[i]+'0');
}
const int inf=1e9+10;
class node{public:int a,b,c,w;}tree[50010<<2];
int a[50010];
void pu(node &x,node l,node r){
	x.a=max(l.a,l.w+r.a);
	x.b=max(r.b,r.w+l.b);
	x.c=max(l.b+r.a,max(l.c,r.c));
	x.w=l.w+r.w;
}
void build(int x,int l,int r){
	if(l==r){
		tree[x]=(node){a[l],a[l],a[l],a[l]};
		return;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	pu(tree[x],tree[x<<1],tree[x<<1|1]);
}
void upd(int x,int l,int r,int pos,int val){
	if(l==r){
		tree[x]=(node){val,val,val,val};
		return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid)upd(x<<1,l,mid,pos,val);
	else upd(x<<1|1,mid+1,r,pos,val);
	pu(tree[x],tree[x<<1],tree[x<<1|1]);
}
node qry(int x,int l,int r,int cl,int cr){
	if(l==cl&&cr==r)return tree[x];
	int mid=(l+r)>>1;
	if(cr<=mid)return qry(x<<1,l,mid,cl,cr);
	if(cl>=mid+1)return qry(x<<1|1,mid+1,r,cl,cr);
	node res;
	pu(res,qry(x<<1,l,mid,cl,mid),qry(x<<1|1,mid+1,r,mid+1,cr));
	return res;
}
int n,q;
int main(){
	n=read();
	for(int i=0;i<n;i++)a[i]=read();
	build(1,0,n-1);
	q=read();
	for(int i=0;i<q;i++){
		int type=read();
		if(type==0){
			int x=read()-1,val=read();
			upd(1,0,n-1,x,val);
		}
		else{
			int l=read()-1,r=read()-1;
			print(qry(1,0,n-1,l,r).c);
			putchar('\n');
		}
	}
	return 0;
}
/*inline? ll or int? size? min max?*/
sol2

\(ddp\) 做法.

考慮兩個 \(dp\) ,

\(f(i)\) 表示以 \(i\) 結束的連續子序列最大值 .

\(g(i)\) 表示區間 \([0,i]\) 的連續子序列最大值 .

考慮轉移方程,

\(f(i)=\max(a_i,f(i-1)+a_i)\)

\(g(i)=\max(f(i),g(i-1))\)\(g(i)=\max(f(i),f(i-1)+a_i,a_i)\)

\(f(i),g(i)\) 都是從 \(f(i-1),g(i-1)\) 轉移過來的,考慮轉移矩陣. 這個的矩陣是廣義矩陣,依舊滿足結合律 .

\[\begin{bmatrix} a_i&−\infty&a_i\\ a_i&0&a_i\\ -\infty&-\infty&0\\ \end{bmatrix} \begin{bmatrix} f(i-1)\\ g(i-1)\\ 0 \end{bmatrix} = \begin{bmatrix} f(i)\\ g(i)\\ 0 \end{bmatrix} \]

這個的矩陣是廣義矩陣,依舊滿足結合律 .

矩陣寫得有點奇怪,因為矩陣的計算要從下標從大往小算 .

不帶修改的時候,矩陣快速冪就可以解決 .

但是帶上修改操作,就需要用線段樹維護,每個節點維護當前區間的轉移矩陣 .

修改和查詢和普通的線段樹一樣,只是 pushup 操作是兩個矩陣相乘 .

合併的時候注意,因為我寫的轉移矩陣下表要從大往小算,所以,合併的時候是右兒子乘左兒子 .

其實也可以寫得正常一點,轉移矩陣就是

\[\begin{bmatrix} f(i-1)&g(i-1)&0 \end{bmatrix} \begin{bmatrix} a_i&a_i&-\infty\\ -\infty&0&-\infty\\ a_i&a_i&0\\ \end{bmatrix} = \begin{bmatrix} f(i),g(i),0 \end{bmatrix} \]

此時下標就正常了,是從左往右合併 .

時間複雜度 : \(\mathrm O(27q\log n)\)

空間複雜度 : \(O(27n)\)

code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	while((ch<'0'||ch>'9')&&(ch!='-'))ch=getchar();
	bool f=false;
	if(ch=='-'){
		f=true;
		ch=getchar();
	}
	int res=0;
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	if(f)res=-res;
	return res;
} 
inline void print(int res){
	if(res==0){
		putchar('0');
		return;
	}
	if(res<0){
		putchar('-');
		res=-res;
	}
	int a[10],len=0;
	while(res>0){
		a[len++]=res%10;
		res/=10;
	}
	for(int i=len-1;i>=0;i--)
		putchar(a[i]+'0');
}
const int inf=1e9+10;
int v[50010<<2];
class node{
public:
	int a[3][3];
	
}t[50010<<2];
inline node operator*(const  node&x,const  node&y){
	node res;
	for(int i=0;i<3;i++)for(int j=0;j<3;j++)
		res.a[i][j]=-inf;
	for(int k=0;k<3;k++){
		for(int i=0;i<3;i++)for(int j=0;j<3;j++){
			if(x.a[i][k]==-inf||y.a[k][j]==-inf)continue;
			res.a[i][j]=max(res.a[i][j],x.a[i][k]+y.a[k][j]);
		}
	}
	return res;
}
node pu(const node&x,const node&y){
	node res;
	for(int i=0;i<3;i++)for(int j=0;j<3;j++)res.a[i][j]=-inf;
	res=x*y;
	return res;
}
void build(int x,int l,int r){
	if(l==r){
		t[x].a[0][0]=v[l];t[x].a[0][1]=-inf;t[x].a[0][2]=v[l];
		t[x].a[1][0]=v[l];t[x].a[1][1]=0;t[x].a[1][2]=v[l];
		t[x].a[2][0]=-inf;t[x].a[2][1]=-inf;t[x].a[2][2]=0;
		return;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	t[x]=pu(t[x<<1|1],t[x<<1]);
/*	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			cout<<t[x].a[i][j]<<" ";
		}
		cout<<endl;
	}
*/
}
void upd(int x,int l,int r,int pos,int val){
	if(l==r){
		t[x].a[0][0]=val;t[x].a[0][1]=-inf;t[x].a[0][2]=val;
		t[x].a[1][0]=val;t[x].a[1][1]=0;t[x].a[1][2]=val;
		t[x].a[2][0]=-inf;t[x].a[2][1]=-inf;t[x].a[2][2]=0;
		return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid)upd(x<<1,l,mid,pos,val);
	else upd(x<<1|1,mid+1,r,pos,val);
	t[x]=pu(t[x<<1|1],t[x<<1]);
/*	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			cout<<t[x].a[i][j]<<" ";
		}
		cout<<endl;
	}
*/
}
node qry(int x,int l,int r,int cl,int cr){
	if(cl==l&&cr==r)return t[x];
	int mid=(l+r)>>1;
	if(cr<=mid)return qry(x<<1,l,mid,cl,cr);
	if(mid+1<=cl)return qry(x<<1|1,mid+1,r,cl,cr);
	return qry(x<<1|1,mid+1,r,mid+1,cr)*qry(x<<1,l,mid,cl,mid); 
}
int n,q;
int main(){
	n=read();
	for(int i=0;i<n;i++)v[i]=read();
	build(1,0,n-1);
	q=read();
	for(int i=0;i<q;i++){
		int type=read();
		if(type==0){
			int id=read()-1,val=read();
			upd(1,0,n-1,id,val);
		}
		else{
			int l=read()-1,r=read()-1;
			node matrix=qry(1,0,n-1,l,r);
			print(max(max(matrix.a[0][2],matrix.a[1][2]),matrix.a[0][3]));
			putchar('\n');
		}
	}
	return 0;
}
/*inline? ll or int? size? min max?*/
/*
4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3
*/