zoukankan      html  css  js  c++  java
  • 【洛谷】P4643 【模板】动态dp

    题解

    在冬令营上听到冬眠的东西,现在都是板子了猫锟真的是好毒瘤啊(雾)

    (立个flag,我去thusc之前要把WC2018T1乱搞过去= =)

    好的,我们可以参考猫锟的动态动态dp的课件,然后你发现你什么都看不懂(菜啊

    但是我们仔细看一看,可以发现用数据结构维护矩阵,那么我们尝试构造一个矩阵

    $egin{bmatrix}
    g_{u,0} & g_{u,0}
    g_{u,1} & 0
    end{bmatrix}
    egin{bmatrix}
    f_{son[u],0}
    f_{son[u],1}
    end{bmatrix}

    egin{bmatrix}
    f_{u,0}
    f_{u,1}
    end{bmatrix}( 其中)g_{u,0}(表示不选u,对于u的子树,除了u的重儿子所在子树,u的轻儿子最大独立集是多少 )g_{u,1}(表示选了u )f_{u,0}(表示不选u,以u为根的子树最大独立集是多少 )f_{u,1}$表示选了u,以u为根的子树最大独立集是多少

    这个矩阵的运算不是加法和乘法,而是加法和取max
    也就是(c_{i,j} = max(a_{i,k} + b_{k,j}))
    也是满足结合律的

    这样我们就可以用一个树链剖分来维护这些矩阵了

    注意一下,合并矩阵的时候是左右合并,但是乘法的时候一定先从右边乘
    举个例子,我们的运算实际是这样的
    一条链:
    3 - 4 - 5
    3是4的父亲,4是5的父亲
    (egin{bmatrix} g_{3,0} & g_{3,0}\ g_{3,1} & 0 end{bmatrix} egin{bmatrix} g_{4,0} & g_{4,0}\ g_{4,1} & 0 end{bmatrix} egin{bmatrix} f_{5,0}\ f_{5,1} end{bmatrix} = egin{bmatrix} f_{3,0}\ f_{3,1} end{bmatrix})
    也就是5先和4的矩阵结合,再和3的矩阵结合

    实际上写代码的时候,既然每一条链的最后一定是一个叶子节点,我们就可以直接把f0设成0,f1设成0去做矩阵乘法,乘上这条链上所有的矩阵作为链顶的f值

    代码

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <map>
    //#define ivorysi
    #define pb push_back
    #define space putchar(' ')
    #define enter putchar('
    ')
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define mo 974711
    #define RG register
    #define MAXN 100005
    #define debug
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 + c - '0';
    	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) putchar('-'),x = -x;
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    const int MOD = 1000000007;
    int mul(int a,int b) {
        return 1LL * a * b % MOD;
    }
    int inc(int a,int b) {
        a = a + b;
        if(a >= MOD) a -= MOD;
        return a;
    }
    
    int fpow(int x,int c) {
        int res = 1,t = x % MOD;
        while(c) {
    	if(c & 1) res = mul(res,t);
    	t = mul(t,t);
    	c >>= 1;
        }
        return res;
    }
    int N,Q;
    int64 val[MAXN],g[MAXN][2],f[MAXN][2];
    int top[MAXN],btm[MAXN],dfn[MAXN],fa[MAXN],dep[MAXN],son[MAXN],idx,siz[MAXN],L[MAXN],pos[MAXN];
    int cnt = 0;
    struct node {
        int to,next;
    }E[MAXN * 2];
    int head[MAXN],sumE;
    struct tr_node {
        int l,r;
        int64 M[2][2];
    }tr[MAXN * 4];
    void add(int u,int v) {
        E[++sumE].to = v;
        E[sumE].next = head[u];
        head[u] = sumE;
    }
    void dfs1(int u) {
        dep[u] = dep[fa[u]] + 1;
        siz[u] = 1;
        for(int i = head[u] ; i ; i = E[i].next) {
    	int v = E[i].to;
    	if(v != fa[u]) {
    	    fa[v] = u;
    	    dfs1(v);
    	    siz[u] += siz[v];
    	    if(siz[v] > siz[son[u]]) son[u] = v;
    	}
        }
    }
    void dfs2(int u) {
        dfn[u] = ++idx;
        L[idx] = u;
        if(!top[u]) {top[u] = u;}
        if(son[u]) {
    	top[son[u]] = top[u];
    	dfs2(son[u]);
    	btm[u] = btm[son[u]]; 
        }
        g[u][1] = val[u];g[u][0] = 0;
        for(int i = head[u] ; i ; i = E[i].next) {
    	int v = E[i].to;
    	if(v != son[u] && v != fa[u]) {
    	    dfs2(v);
    	    g[u][0] += max(f[v][0],f[v][1]);
    	    g[u][1] += max(0LL,f[v][0]);
    	}
        }
        f[u][1] = g[u][1] + max(f[son[u]][0],0LL);
        f[u][0] = g[u][0] + max(f[son[u]][1],f[son[u]][0]);
        if(!son[u]) btm[u] = u;
    }
    void update(int u) {
        int L = u << 1,R = u << 1 | 1;
        tr[u].M[0][0] = max(tr[L].M[0][0] + tr[R].M[0][0],tr[L].M[0][1] + tr[R].M[1][0]);
        tr[u].M[0][1] = max(tr[L].M[0][0] + tr[R].M[0][1],tr[L].M[0][1] + tr[R].M[1][1]);
        tr[u].M[1][0] = max(tr[L].M[1][0] + tr[R].M[0][0],tr[L].M[1][1] + tr[R].M[1][0]);
        tr[u].M[1][1] = max(tr[L].M[1][0] + tr[R].M[0][1],tr[L].M[1][1] + tr[R].M[1][1]);
    }
    void build(int u,int l,int r) {
        tr[u].l = l;tr[u].r = r;
        if(l == r) {
    	int v = L[l];
    	tr[u].M[0][0] = g[v][0];tr[u].M[0][1] = g[v][0];
    	tr[u].M[1][0] = g[v][1];tr[u].M[1][1] = 0;
    	pos[v] = u;
    	return ;
        }
        int mid = (l + r) >> 1;
        build(u << 1,l,mid);build(u << 1 | 1,mid + 1,r);
        update(u);
    }
    void Query(int u,int L,int R,int64 &f0,int64 &f1) {
        if(tr[u].l == L && tr[u].r == R) {
    	int64 x = max(f0 + tr[u].M[0][0],f1 + tr[u].M[0][1]);
    	int64 y = max(f0 + tr[u].M[1][0],f1 + tr[u].M[1][1]);
    	f0 = x;f1 = y;
    	return;
        }
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(R <= mid) Query(u << 1,L,R,f0,f1);
        else if(L > mid) Query(u << 1 | 1,L,R,f0,f1);
        else {
    	Query(u << 1 | 1,mid + 1,R,f0,f1);
    	Query(u << 1,L,mid,f0,f1);
        }
    }
    void Change(int x) {
        int t = pos[x] >> 1;
        while(t) {
    	update(t);
    	t >>= 1;
        }
    }
    void Change_tr(int x) {
        while(1) {
    	int a = top[x];
    	if(fa[a] != 0) {
    	    g[fa[a]][0] -= max(f[a][0],f[a][1]);
    	    g[fa[a]][1] -= max(f[a][0],0LL);
    	}
    	f[a][0] = 0;f[a][1] = 0;
    	Query(1,dfn[top[x]],dfn[btm[x]],f[a][0],f[a][1]);
    	if(fa[a] == 0) break;
    	g[fa[a]][0] += max(f[a][0],f[a][1]);
    	g[fa[a]][1] += max(f[a][0],0LL);
    	x = fa[a];
    	tr[pos[x]].M[0][0] = tr[pos[x]].M[0][1] = g[x][0];
    	tr[pos[x]].M[1][0] = g[x][1];tr[pos[x]].M[1][1] = 0;
    	Change(x);
        }
    }
    void Init() {
        read(N);read(Q);
        for(int i = 1 ; i <= N ; ++i) read(val[i]);
        int u,v;
        for(int i = 1 ; i < N ; ++i) {
    	read(u);read(v);
    	add(u,v);add(v,u);
        }
        dfs1(1);
        dfs2(1);
        build(1,1,N);
    }
    void Solve() {
        int x;int64 y;
        
        while(Q--) {
    	++cnt;
    	read(x);read(y);
    	g[x][1] = g[x][1] - val[x] + y;
    	tr[pos[x]].M[1][0] = g[x][1];
    	val[x] = y;
    	Change(x);
    	Change_tr(x);
    	out(max(f[1][0],f[1][1]));enter;
    	
        }
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Init();
        Solve();
        return 0;
    }
    
  • 相关阅读:
    前端之CSS1
    前端之HTML
    Python进阶之网络编程
    SparkSQL——HiveContext的使用
    SparkSQL——SQLContext的使用
    语义分析
    SLR(1)分析法分析过程
    算符优先分析法
    LL(1)语法分析
    递归下降分析分析法
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9118007.html
Copyright © 2011-2022 走看看