#线段树,矩阵乘法#LOJ 3264「ROIR 2020 Day 2」海报

题目


分析

\(dp[i][0/1/2/3]\)表示以\(i\)结尾1的长度为0/1/2/3的最大值,
那么

\[\begin{cases}dp[i][0]=\max\{dp[i-1][\dots]\}\\dp[i][x]=dp[i-1][x-1]+a[i],x>0\end{cases} \]

发现这个环只要保证开头和结尾的\(0/1/2/3\)相同即可,单点修改直接在线段树上维护广义矩阵乘法


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
typedef long long lll;
const lll inf=1e15;
const int N=40011;
int n,Q,a[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(lll ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline lll max(lll a,lll b){return a>b?a:b;}
struct maix{
	lll p[4][4];
	inline void Clear(){
		for (rr int i=0;i<4;++i)
		for (rr int j=0;j<4;++j)
			p[i][j]=-inf;
	}
	inline maix operator *(const maix &B)const{
		rr maix C; C.Clear();
		for (rr int i=0;i<4;++i)
		for (rr int j=0;j<4;++j)
		for (rr int k=0;k<4;++k)
			C.p[i][j]=max(C.p[i][j],p[i][k]+B.p[k][j]);
		return C;
	}
}w[N<<2];
inline void build(int k,int l,int r){
	if (l==r){
		rr maix C; C.Clear();
		C.p[0][0]=C.p[1][0]=C.p[2][0]=C.p[3][0]=0;
		C.p[0][1]=C.p[1][2]=C.p[2][3]=a[l],w[k]=C;
		return;
	}
	rr int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	w[k]=w[k<<1]*w[k<<1|1];
}
inline void update(int k,int l,int r,int x){
	if (l==r){
		w[k].p[0][1]=w[k].p[1][2]=w[k].p[2][3]=a[l];
		return;
	}
	rr int mid=(l+r)>>1;
	if (x<=mid) update(k<<1,l,mid,x);
	    else update(k<<1|1,mid+1,r,x);
	w[k]=w[k<<1]*w[k<<1|1];
}
inline void query(maix A){
	rr lll ans=0;
	for (rr int i=0;i<4;++i)
		ans=max(ans,A.p[i][i]);
	print(ans),putchar(10);
}
signed main(){
	n=iut();
	for (rr int i=1;i<=n;++i) a[i]=iut();
	build(1,1,n),query(w[1]);
	for (rr int Q=iut();Q;--Q){
		rr int x=iut(),y=iut(); a[x]=y;
		update(1,1,n,x),query(w[1]);
	}
	return 0;
}
posted @ 2021-07-19 14:47  lemondinosaur  阅读(100)  评论(0编辑  收藏  举报