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);
}
posted @ 2021-07-21 14:56  zlc0405  阅读(45)  评论(0编辑  收藏  举报