最近在学个玄学东西,动态dp。在这里稍微记录一下
抛个序列上的动态dp题(树上的还不怎么会写,太玄学了。。。)
带单点修改的最大字段和
普通的状态转移嘛。。很简单
动态dp这玩意是构造矩阵嘛。。然后把各种转移玄学的改成(乘法???)运算,这里的(乘法)必须满足结合律
可这玩意咋构造矩阵呢。。。
大家应该都知道斐波那契数列矩阵构造,很简单
可这玩意是f[i]=f[i-1]+f[i-2]有加法乘法,,,,这里来个max什么鬼。。我们把这个式子改写一下
这玩意是啥?分配律!!!
大家都应该知道矩阵乘法满足结合律,为啥满足结合律呢?
因为有 乘法对加法满足分配律
那么加法对max/min这玩意也有分配律对不???对的!!
我们都知道矩阵乘法运算规则
既然普通的矩阵乘法是两个两个乘再全部加起来,那我们可不可以两个两个加起来再取max!!
这玩意是满足结合律的!!
好了,我们这回可以改写一下那个状态转移方程了
尝试利用构造矩阵!
完美对不对!!!
然后有了这玩意,我们该怎么做呢?
观察一下,对于左边那个矩阵,他有个 ,我们是不是可以对于每一个数字都创建该个这个矩阵,然后对于每个询问我们是不是可以把区间内每个矩阵做一遍乘法,然后再乘一遍答案是不是就出来了,记住这里的
到这里大功告成!!!
贴一遍代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=2e5+10;
struct mat{
int n,m;
int** A;
inline mat():n(0),m(0){}
inline void setsize(int sn,int sm){
n=sn,m=sm;
A=new int*[n];
for(register int i=0;i<n;i++){
A[i]=new int[m];
for(register int j=0;j<m;j++){
A[i][j]=-inf;
}
}
}
inline mat operator * (const mat& other)const{
mat ret;
ret.setsize(n,other.m);
for(register int i=0;i<n;i++){
for(register int j=0;j<other.m;j++){
for(register int k=0;k<m;k++){
ret.A[i][j]=max(ret.A[i][j],A[i][k]+other.A[k][j]);
}
}
}
return ret;
}
inline mat operator *= (const mat& other){
(*this)=(*this)*other;
return (*this);
}
};
inline void changedata(mat& d,int v){
d.A[0][0]=v,d.A[0][1]=-inf,d.A[0][2]=v;
d.A[1][0]=v,d.A[1][1]=0,d.A[1][2]=v;
d.A[2][0]=-inf,d.A[2][1]=-inf,d.A[2][2]=0;
}
mat lstres;
int n,q;
struct segtree{
mat c[maxn<<2];
segtree(){
for(register int i=0;i<maxn;i++){
c[i].setsize(3,3);
}
}
inline int lson(int k){
return k<<1;
}
inline int rson(int k){
return k<<1|1;
}
void change(int k,int l,int r,int p,int v){
if(l==r){
changedata(c[k],v);
return;
}
int mid=(l+r)>>1;
if(p<=mid){
change(lson(k),l,mid,p,v);
}else{
change(rson(k),mid+1,r,p,v);
}
c[k]=c[lson(k)]*c[rson(k)];
}
mat query(int k,int l,int r,int sl,int sr){
if(sl<=l&&sr>=r){
return c[k];
}
int mid=(l+r)>>1;
mat ret;
if(sl<=mid){
ret=query(lson(k),l,mid,sl,sr);
}
if(mid+1<=sr){
if(ret.n>0){
ret*=query(rson(k),mid+1,r,sl,sr);
}else{
ret=query(rson(k),mid+1,r,sl,sr);
}
}
return ret;
}
};
segtree seg;
inline int read(){
int res=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-f;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f*res;
}
void write(int x){
if(x<0){
x=-x;
putchar('-');
}
if(x>9){
write(x/10);
}
putchar(x%10+'0');
}
int main(){
int n=read();
for(int i=1;i<=n;i++){
int x=read();
seg.change(1,1,n,i,x);
}
int q=read();
lstres.setsize(3,1);
lstres.A[0][0]=-inf,lstres.A[1][0]=-inf,lstres.A[2][0]=0;
while(q--){
int cmd=read(),x=read(),y=read();
if(cmd==0){
seg.change(1,1,n,x,y);
}else{
mat ans=seg.query(1,1,n,x,y)*lstres;
write(ans.A[1][0]);
putchar('\n');
}
}
return 0;
}