题解 P3097 【[USACO13DEC]Optimal Milking G】
来补一个动态 dp 做法。
题意大致就是单点修改求最大独立集
暴力 dp 大概就是
最后是要求
考虑这个东西怎么转为矩阵形式。
这里我们定义矩阵乘法为
这个东西是满足结合律的。
于是上面那个暴力 dp 可以看成是
然后用线段树维护矩阵乘即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ls p<<1
#define rs p<<1|1
const int N=40000+5;
// f[i][0]=max(f[i-1][0],f[i-1][1])
// f[i][1]=f[i-1][0]+a[i]
// | 0 0 |
// | a_i -inf |
struct mat{
int a[2][2];
mat(){
memset(a,-0x3f,sizeof(a));
}
mat operator *(const mat &b) const{
mat res;
for(int i=0;i<2;++i)
for(int j=0;j<2;++j)
for(int k=0;k<2;++k)
res.a[i][j]=max(res.a[i][j],a[i][k]+b.a[k][j]);
return res;
}
}tr[N<<2];
int a[N];
void pushup(int p){
tr[p]=tr[rs]*tr[ls];
}
void build(int p,int l,int r){
if(l==r){
tr[p].a[0][0]=0;
tr[p].a[0][1]=0;
tr[p].a[1][0]=a[l];
tr[p].a[1][1]=-0x3f3f3f3f;
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(p);
}
void upt(int p,int l,int r,int pos,int v){
if(l==r){
tr[p].a[0][0]=0;
tr[p].a[0][1]=0;
tr[p].a[1][0]=v;
tr[p].a[1][1]=-0x3f3f3f3f;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) upt(ls,l,mid,pos,v);
else upt(rs,mid+1,r,pos,v);
pushup(p);
}
int main(){
long long ans=0;
int n,q;
cin>>n>>q;
for(int i=1;i<=n;++i)
cin>>a[i];
int pos,v;
build(1,1,n);
mat res,tmp;
res.a[0][0]=0;res.a[0][1]=0;
while(q--){
cin>>pos>>v;
upt(1,1,n,pos,v);
tmp=res*tr[1];
ans+=max(tmp.a[0][0],tmp.a[0][1]);
//cout<<max(tmp.a[0][0],tmp.a[0][1])<<endl;
}
cout<<ans;
return 0;
}