我是塔兰图拉狼|

狼蛛之家

园龄:3年2个月粉丝:3关注:1

动态 DP

P6021

有一个显然的 O(n2) DP,但是过不了,需要优化!

观察到这个 DP 是 min,+ 卷积的形式,所以可以写成矩阵乘法!

矩阵乘法具有优良的性质:它满足结合律!

所以直接使用树剖来维护矩乘的信息,然后就做完了!

本题代码
#include<bits/stdc++.h>
#define end xiaoheige
#define int long long
using namespace std;
const int maxn = 200005, inf = 1e18;
int n, m;
struct edge {int y, nxt;} e[maxn * 2];
int hd[maxn], num;
inline void join(int x, int y){e[++num] = (edge){y, hd[x]}; hd[x] = num;}
struct mat{
int ele[2][2];
mat(int type = 0) {
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
ele[i][j] = inf;
if(type == 1)
for(int i=0;i<2;i++)
ele[i][i] = 0;
}
int& operator()(const int ix, const int iy){return ele[ix][iy];}
inline friend mat operator*(mat mx, mat my) {
mat res(0);
for(int i=0;i<2;i++)
for(int k=0;k<2;k++)
for(int j=0;j<2;j++)
res(i,j)=min(res(i,j), mx(i,k)+my(k,j));
return res;
}
};
int val[maxn], f[maxn];
mat g[maxn];
int dep[maxn], pa[maxn], siz[maxn], son[maxn], top[maxn], dfn[maxn], rev[maxn], end[maxn], cnt = 0;
void dfs1(int u, int fa) {
siz[u] = 1; dep[u] = dep[fa] + 1; pa[u] = fa;
for(int i=hd[u];i;i=e[i].nxt) {
int v = e[i].y;
if(v == fa) continue;
dfs1(v, u);
siz[u] += siz[v];
if(siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs2(int u, int t) {
dfn[u] = ++cnt; rev[cnt] = u; top[u] = t; end[t] = max(end[t], cnt);
g[u](0, 0) = 0; g[u](0, 1) = val[u];
g[u](1, 0) = inf; g[u](1, 1) = 0;
f[u] = 0;
if(son[u]) {dfs2(son[u], t); f[u] += f[son[u]];}
else g[u](0, 0) = inf;
for(int i=hd[u];i;i=e[i].nxt) {
int v = e[i].y;
if(v == pa[u] || v == son[u]) continue;
dfs2(v, v);
g[u](0, 0) += f[v];
f[u] += f[v];
}
if(!son[u]) f[u] = val[u];
else f[u] = min(f[u], val[u]);
}
struct jiji{int l, r; mat val;}t[maxn<<2];
inline void pushUp(int k){t[k].val = t[k<<1].val*t[k<<1|1].val;}
void build(int l, int r, int k){
t[k].l = l; t[k].r = r;
if(l == r) {t[k].val = g[rev[l]]; return ;}
int mid = t[k].l+t[k].r>>1;
build(l, mid, k<<1); build(mid+1, r, k<<1|1);
pushUp(k);
}
void update(int x, int k){
if(t[k].l == t[k].r) {t[k].val = g[rev[x]]; return;}
int mid = t[k].l+t[k].r>>1;
if(x <= mid) update(x, k<<1);
else update(x, k<<1|1);
pushUp(k);
}
mat query(int x, int y, int k) {
if(t[k].l == x && t[k].r == y) return t[k].val;
int mid = t[k].l+t[k].r>>1;
if(y <= mid) return query(x, y, k<<1);
else if(x >= mid+1) return query(x, y, k<<1|1);
else return query(x, mid, k<<1)*query(mid+1, y, k<<1|1);
}
inline void updatePath(int x, int z) {
val[x] += z;
g[x](0, 1) = val[x];
mat bef, aft;
while(x) {
bef = query(dfn[top[x]], end[top[x]], 1);
update(dfn[x], 1);
aft = query(dfn[top[x]], end[top[x]], 1);
x = pa[top[x]];
g[x](0, 0) += min(aft(0, 0), aft(0, 1)) - min(bef(0, 0), bef(0, 1));
}
}
inline int querySubtree(int x) {
mat res = query(dfn[x], end[x], 1);
return min(res(0, 0), res(0, 1));
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for(int i=1;i<=n;++i) cin >> val[i];
for(int i=1;i<n;i++) {
int a, b; cin >> a >> b;
join(a, b); join(b, a);
}
dfs1(1, 0);
dfs2(1, 1);
for(int i=1;i<=n;i++) end[i] = end[top[i]];
build(1, n, 1);
cin >> m;
while(m--) {
char opt; int x; int z; cin>>opt;
if(opt == 'C') {cin >> x >> z; updatePath(x, z);}
else {cin >> x; printf("%lld\n",querySubtree(x));}
}
return 0;
}
posted @   狼蛛之家  阅读(12)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起