P3097 [USACO13DEC]Optimal Milking G(线段树维护矩阵乘法)
题意简述:给定n个点排成一排,每个点有一个点权,多次改变某个点的点权并将最大点独立集计入答案,输出最终的答案
定义f(i,0)为第i个数不取,定义f(i,1)为第i个数取。
转移式子:
f(i,0)=max(f(i-1,0),f(i-1,1))
f(i,1)=max(f(i-1,0)+a[i])
可以用矩阵表示这个过程:
0 a[i]
0 -inf
用线段树维护一下这个矩阵乘法,就做完了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
typedef long long ll;
struct matrix {
ll m[3][3];
};
void ccpy (matrix &x,matrix &y) {
for (int i=1;i<=2;i++) {
for (int j=1;j<=2;j++) {
x.m[i][j]=y.m[i][j];
}
}
}
void mul (matrix &ans,matrix a,matrix b) {
for (int i=1;i<=2;i++) {
for (int j=1;j<=2;j++) {
ans.m[i][j]=max(a.m[i][j],b.m[i][j]);
}
}
for (int k=1;k<=2;k++) {
for (int i=1;i<=2;i++) {
for (int j=1;j<=2;j++) {
ans.m[i][j]=max(ans.m[i][j],a.m[i][k]+b.m[k][j]);
}
}
}
}
int n,a[maxn],m;
struct node {
int l,r;
matrix sum;
}segTree[maxn<<2];
void build (int i,int l,int r) {
segTree[i].l=l;
segTree[i].r=r;
if (l==r) {
segTree[i].sum.m[1][1]=0;
segTree[i].sum.m[1][2]=a[l];
segTree[i].sum.m[2][1]=0;
segTree[i].sum.m[2][2]=-1e10;
return;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
mul(segTree[i].sum,segTree[i<<1].sum,segTree[i<<1|1].sum);
}
void up (int i,int p,int v) {
if (segTree[i].l==p&&segTree[i].r==p) {
a[segTree[i].l]=v;
segTree[i].sum.m[1][1]=0;
segTree[i].sum.m[1][2]=v;
segTree[i].sum.m[2][1]=0;
segTree[i].sum.m[2][2]=-1e10;
return;
}
int mid=(segTree[i].l+segTree[i].r)>>1;
if (p<=mid) up(i<<1,p,v);
if (p>mid) up(i<<1|1,p,v);
mul(segTree[i].sum,segTree[i<<1].sum,segTree[i<<1|1].sum);
}
int main () {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",a+i);
long long ans=0;
build(1,1,n);
while (m--) {
int x,y;
scanf("%d%d",&x,&y);
up(1,x,y);
ans+=max(segTree[1].sum.m[1][1],segTree[1].sum.m[1][2]);
}
printf("%lld\n",ans);
}