zoukankan      html  css  js  c++  java
  • 【SP1716】GSS3 Can you answer these queries III

    题目

    题目链接:https://www.luogu.com.cn/problem/SP1716
    \(n\) 个数,\(q\) 次操作
    操作0 x y\(A_x\) 修改为\(y\)
    操作1 l r询问区间\([l, r]\) 的最大子段和

    思路

    经典的最大子段和问题。解决这类问题一般有两种做法:

    1. 线段树维护区间最大子段和,最大前缀和最大后缀。
    2. 动态\(dp\)

    方法1在很久以前就做过了,刚接触\(ddp\),来做一下\(ddp\)的模板题。
    我们考虑如果是静态最大子段和应该怎么做。设\(f[i]\)表示以\(i\)结尾的最大后缀,那么有

    \[f[i]=max(f[i-1]+a[i],a[i]) \]

    则答案就是\(\max^{n}_{i=1}f[i]\)
    考虑用矩阵乘法优化,但是一般的矩阵乘法是不支持\(\min,\max\)两种操作的,但是矩阵乘法满足分配律,而\(\max\)也依然满足分配律,所以我们令

    \[f_{i,j}=\max^{n}_{k=1}(a_{i,k}+b_{k,j}) \]

    再进行矩阵乘法。
    那么可以写出转移矩阵

    \[\begin{bmatrix} f[i]\\ ans[i]\\ 0 \end{bmatrix} \begin{bmatrix} a[i] & -\infty & a[i]\\ a[i] & 0 & a[i]\\ -\infty & -\infty &0 \end{bmatrix} = \begin{bmatrix} a[i+1]\\ ans[i+1]\\ 0 \end{bmatrix}\]

    其中\(ans[i]=\max^{n}_{i=1}f[i]\)
    考虑到矩阵乘法满足结合律,所以我们可以用线段树维护矩阵区间积。这样就可以支持单点修改和区间查询。
    时间复杂度\(O(q·k^3\log^2 n )\),其中\(k=3\)

    代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=50010,Inf=1e9;
    int n,Q,opt,x,y,a[N];
    
    struct matrix
    {
    	int a[4][4];
    	
    	friend matrix operator *(matrix a,matrix b)
    	{
    		matrix c;
    		memset(c.a,-0x3f3f3f3f,sizeof(c.a));
    		for (int i=1;i<=3;i++)
    			for (int j=1;j<=3;j++)
    				for (int k=1;k<=3;k++)
    					c.a[i][j]=max(c.a[i][j],a.a[i][k]+b.a[k][j]);
    		return c;
    	}
    };
    
    struct SegTree
    {
    	matrix f[N*4];
    	int l[N*4],r[N*4];
    	
    	void pushup(int x)
    	{
    		f[x]=f[x*2]*f[x*2+1];
    	}
    	
    	void build(int x,int ql,int qr)
    	{
    		l[x]=ql; r[x]=qr;
    		if (ql==qr)
    		{
    			f[x].a[1][1]=f[x].a[1][3]=f[x].a[2][1]=f[x].a[2][3]=a[ql];
    			f[x].a[1][2]=f[x].a[3][1]=f[x].a[3][2]=-Inf;
    			f[x].a[2][2]=f[x].a[3][3]=0;
    			return;
    		}
    		int mid=(ql+qr)>>1;
    		build(x*2,ql,mid); build(x*2+1,mid+1,qr);
    		pushup(x);
    	}
    	
    	void update(int x,int k,int val)
    	{
    		if (l[x]==k && r[x]==k)
    		{
    			f[x].a[1][1]=f[x].a[1][3]=f[x].a[2][1]=f[x].a[2][3]=val;
    			return;
    		}
    		int mid=(l[x]+r[x])>>1;
    		if (k<=mid) update(x*2,k,val);
    			else update(x*2+1,k,val);
    		pushup(x);
    	}
    	
    	matrix ask(int x,int ql,int qr)
    	{
    		if (l[x]==ql && r[x]==qr)
    			return f[x];
    		int mid=(l[x]+r[x])>>1;
    		if (qr<=mid) return ask(x*2,ql,qr);
    		if (ql>mid) return ask(x*2+1,ql,qr);
    		return ask(x*2,ql,mid)*ask(x*2+1,mid+1,qr);
    	}
    }seg;
    
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	seg.build(1,1,n);
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		scanf("%d%d%d",&opt,&x,&y);
    		if (!opt) seg.update(1,x,y);
    		else
    		{
    			matrix ans=seg.ask(1,x,y);
    			printf("%d\n",max(ans.a[2][1],ans.a[2][3]));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    说一下 session 的工作原理?
    session 和 cookie 有什么区别?
    说一下 JSP 的 4 种作用域?
    jsp有哪些内置对象?作用分别是什么?
    MVC的各个部分都有那些技术来实现?如何实现?
    request.getAttribute()和 request.getParameter()有何区别?
    Servlet API中forward()与redirect()的区别?
    jsp和servlet的区别、共同点、各自应用的范围?
    说一说Servlet的生命周期?
    如何从CDN加载jQuery?
  • 原文地址:https://www.cnblogs.com/stoorz/p/12297121.html
Copyright © 2011-2022 走看看