Luogu 4751 动态DP 模板

题面

动态求最大独立集

题解

树剖后用矩阵转移。
具体见Tweetuzki的洛谷博客

CODE

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
inline void read(int &x) {
	char ch; int flg=1; while(!isdigit(ch=getc()))if(ch=='-')flg=-flg;
	for(x=ch-'0';isdigit(ch=getc());x=x*10+ch-'0'); x*=flg;
}
const int MAXN = 1000005;
const int INF = 1000000000;
int n, m, V[MAXN], fir[MAXN], nxt[MAXN<<1], to[MAXN<<1], cnt;
inline void link(int u, int v) {
	to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
	to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
}
int tmr, fa[MAXN], dfn[MAXN], tp[MAXN], bt[MAXN], son[MAXN], sz[MAXN], seq[MAXN];
struct mat {
	int a[2][2];
	int* operator[](int x) { return a[x]; }
	mat operator*(const mat &o)const {
		mat re;
		for(int i = 0; i < 2; ++i)
			for(int j = 0; j < 2; ++j)
				re.a[i][j] = max(a[i][0]+o.a[0][j], a[i][1]+o.a[1][j]);
		return re;
	}
}t[MAXN<<2], val[MAXN];
void dfs1(int u, int ff) {
	fa[u] = ff; sz[u] = 1;
	for(int i = fir[u], v; i; i = nxt[i])
		if((v=to[i]) != ff) {
			dfs1(v, u), sz[u] += sz[v];
			(sz[v] > sz[son[u]]) && (son[u] = v);
		}
}
int f[MAXN][2];
void dfs2(int u, int top) {
	tp[u] = top; bt[top] = u;
	seq[dfn[u]=++tmr] = u;
	if(son[u]) dfs2(son[u], top);
	for(int i = fir[u], v; i; i = nxt[i])
		if((v=to[i]) != fa[u] && v != son[u])
			dfs2(v, v);
}
void dp(int u) {
	f[u][0] = 0; f[u][1] = V[u];
	for(int i = fir[u], v; i; i = nxt[i])
		if((v=to[i]) != fa[u])
			dp(v),
			f[u][0] += max(f[v][0], f[v][1]),
			f[u][1] += f[v][0];
}
void build(int i, int l, int r) {
	if(l == r) {
		int f0 = 0, f1 = V[seq[l]];
		for(int j = fir[seq[l]], v; j; j = nxt[j])
			if((v=to[j]) != fa[seq[l]] && v != son[seq[l]])
				f0 += max(f[v][0], f[v][1]),
				f1 += f[v][0];
		val[l] = t[i] = (mat){ {{f0, f0} , {f1, -INF}} };
		return;
	}
	int mid = (l + r) >> 1;
	build(i<<1, l, mid);
	build(i<<1|1, mid+1, r);
	t[i] = t[i<<1] * t[i<<1|1];
}
void update(int i, int l, int r, int x) {
	if(l == r) { t[i] = val[l]; return; }
	int mid = (l + r) >> 1;
	if(x <= mid) update(i<<1, l, mid, x);
	else update(i<<1|1, mid+1, r, x);
	t[i] = t[i<<1] * t[i<<1|1];
}
mat query(int i, int l, int r, int x, int y) {
	if(x == l && r == y) return t[i];
	int mid = (l + r) >> 1;
	if(y <= mid) return query(i<<1, l, mid, x, y);
	if(x > mid) return query(i<<1|1, mid+1, r, x, y);
	return query(i<<1, l, mid, x, mid) * query(i<<1|1, mid+1, r, mid+1, y);
}
void modify(int u, int W) {
	val[dfn[u]][1][0] += W-V[u]; V[u]=W;
	while(u) {
		mat pre = query(1, 1, n, dfn[tp[u]], dfn[bt[tp[u]]]);
		update(1, 1, n, dfn[u]);
		mat now = query(1, 1, n, dfn[tp[u]], dfn[bt[tp[u]]]);
		u = fa[tp[u]]; if(!u) return; int x = dfn[u];
		int p0 = pre[0][0], p1 = pre[1][0];
		int n0 = now[0][0], n1 = now[1][0];
		val[x][0][0] = val[x][0][1] = val[x][0][0] + max(n0, n1) - max(p0, p1);
		val[x][1][0] = val[x][1][0] + n0 - p0;
	}
}
int main () {
	read(n), read(m);
	for(int i = 1; i <= n; ++i) read(V[i]);
	for(int i = 1, u, v; i < n; ++i) read(u), read(v), link(u, v);
	dfs1(1, 0), dfs2(1, 1), dp(1);
	build(1, 1, n);
	int x, y, lstans=0;
	while(m--) {
		read(x), read(y); x^=lstans; modify(x, y);
		mat ans = query(1, 1, n, 1, dfn[bt[1]]);
		printf("%d\n", lstans=max(ans[0][0], ans[1][0]));
	}
}

加强版只过80分

posted @ 2019-12-14 14:50  _Ark  阅读(83)  评论(0编辑  收藏  举报