zoukankan      html  css  js  c++  java
  • 2019杭电/牛客多校待补题和已补题

    rt

    @

    HDU第八场

    HDU6662 Acesrc and Travel 树形DP

    题意:

    • A,B两个人,每个节点有两个属性(a_i,b_i),A先选一个节点,B选相邻下一个节点,交替选直到没法选。A想让(sum (a_i-b_i))最大,B想让(sum (b_i-a_i))最大。两人都足够聪明,问最后(sum (a_i-b_i))是多少。

    分析:

    • 上面规矩的意思可以说:B想让(sum (a_i-b_i))最小,A想让(sum (b_i-a_i))最小。
    • A选了(u),若此时(u)的儿子全是叶子,B肯定会帮A选(sum (b_i-a_i))最大的路径,此贡献是(a_u-b_u- max(sum (b_i-a_i))),这也是(sum (a_i-b_i))最小的路径。
    • B选了(u),若此时(u)的儿子全是叶子,A肯定会帮B选(sum (a_i-b_i))最大的路径,此贡献是(a_u-b_u+ max(sum (a_i-b_i))),这也是(sum (b_i-a_i))最小的路径。
    • 记录(dp1[i][0])表示双方采取最优策略下(i)子树向下路径中(sum (a_i-b_i))的最小值,(dp1[i][1])为次小值;(dp2[i][0])表示双方采取最优策略下(i)子树向下中(sum (b_i-a_i))的最小值,(dp2[i][1])为次小值。
    • 若以节点(x)为根开始做上面树形DP,则(dp1[x][0])为此时的答案。为统计出每个节点为根时的答案,我们先随便从一个点开始一遍树形DP,然后从同一点开始做换根DP(也就是用父亲的信息更新自己作为根时的贡献。
    • 转移方程:(dp1[u][0] = ar[u]-br[u] - max(dp2[v][0]); vin son[u])(dp2[u][0] = ar[u]-br[u] - max(dp1[v][0]); vin son[u])
    • 换根DP时:双方最优策略下:对每个节点记录它向上路径中最小的(sum(a_i-b_i))=TMP[u],min(dp1[u][0],TMP[u])是u为根时的答案。
    • 为记录TMP[u]还需记录sta[u]表示u节点向上路径中最大的(sum(a_i-b_i)).
    /*
    在AB足够聪明的情况下,A要a-b最大值,答案是dp1[u][0]=min(sum (a_i-b_i)) = ar[u]-br[u]-dp2[u][0],在u的儿子中减去min(sum b_i-a_i)也就是加上max(sum a_i-b_i)),用最大的sum a_i-b_i更新答案即可。dp2[u][0]也是用最大的$sum b_i-a_i$更新答案。
    换根DP时:双方最优策略下:对每个节点记录它向上路径中最小的$sum(a_i-b_i)$=TMP[u],min(dp1[u][0],TMP[u])是u为根时的答案。
    为记录TMP[u]还需记录sta[u]表示u节点向上路径中最大的$sum(a_i-b_i)$.
    
    本题用最大值来更新最小值,和用最小值来更新最大值,答案是最小值,这有点博弈感觉把。
    */
    const int MXN = 1e6 + 7;
    const int MXE = 1e6 + 7;
    int n, m;
    LL ar[MXN], br[MXN];
    vector<int> mp[MXN];
    LL dp1[MXN][2], dp2[MXN][2], TMP[MXN];
    int son[MXN][2], fa[MXN], num[MXN];
    LL ans;
    void dfs1(int u, int ba) {//a - b的minsum, b - a的minsum
        dp1[u][0] = dp1[u][1] = INFLL;
        dp2[u][0] = dp2[u][1] = INFLL;
        fa[u] = ba;num[u] = 0;
        for(auto v: mp[u]) {
            if(v == ba) continue;
            dfs1(v, u);
            num[u]++;
            if(ar[u] - br[u] - dp2[v][0] < dp1[u][0]) {
                son[u][0] = v;
                dp1[u][1] = dp1[u][0];
                dp1[u][0] = ar[u] - br[u] - dp2[v][0];
            }else dp1[u][1] = sml(dp1[u][1], ar[u] - br[u] - dp2[v][0]);
            if(br[u] - ar[u] - dp1[v][0] < dp2[u][0]) {
                son[u][1] = v;
                dp2[u][1] = dp2[u][0];
                dp2[u][0] = br[u] - ar[u] - dp1[v][0];
            }else dp2[u][1] = sml(dp2[u][1], br[u] - ar[u] - dp1[v][0]);
        }
        if(num[u] == 0) dp1[u][0] = dp1[u][1] = ar[u] - br[u], dp2[u][0] = dp2[u][1] = br[u] - ar[u];
    }
    LL tmp, sta[MXN];
    void dfs2(int u, int ba) {
    	for(auto v: mp[u]) {
    		if(v == ba) continue;
    		tmp = dp1[v][0];
    		if(v == son[u][1]) {
    			tmp = dp2[u][1];
    		}else {
    			tmp = dp2[u][0];
    		}
    		int aim = 4;
    //		if(v == aim) debug(tmp, u, mp[u].size())
    		if(u != 1) tmp = sml(tmp, -sta[u]);//a-b max
    		if(num[u] == 1) {
    		    if(num[v] == 0) ans = big(ans,  TMP[v] = ar[v] - br[v] + sta[u]);
    		    else ans = big(ans, sml(dp1[v][0], TMP[v] = ar[v] - br[v] + sta[u]));
    //		    debug(u, v, ans, dp1[v][0], ar[v] - br[v], sta[u])
    		}
    		else {
    		    if(num[v] == 0) ans = big(ans, TMP[v] = ar[v] - br[v] - tmp);
    		    else ans = big(ans, sml(dp1[v][0], TMP[v] = ar[v] - br[v] - tmp));
    		}
    //		if(v == aim) debug(tmp, sta[u], mp[v].size())
    		if(v == son[u][0]) {
    		    tmp = dp1[u][1];
    		}else {
    		    tmp = dp1[u][0];
    		}// a-b max  b-a min
    		if(num[u] == 1) sta[v] = ar[v] - br[v] + TMP[u];
    		else {
    		    if(u == 1) sta[v] = ar[v] - br[v] + tmp;
    		    else sta[v] = ar[v] - br[v] + sml(tmp, TMP[u]);//a-b max b - a min
    		}
    //		debug(u, v, ans, son[u][1]);
    		dfs2(v, u);
    	}
    }
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
    //    freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
    #endif
        int tim = read();
        while(tim --) {
            n = read();
            for(int i = 1; i <= n; ++i) ar[i] = read(), mp[i].clear();
            for(int i = 1; i <= n; ++i) br[i] = read();
            for(int i = 1, a, b; i < n; ++i) {
                a = read(), b = read();
                mp[a].eb(b), mp[b].eb(a);
            }
            dfs1(1, 0);
            for(int i = 1; i <= n; ++i) {
    //            printf("%d %d %lld %lld %lld %lld
    ", son[i][0], son[i][1], dp1[i][0], dp1[i][1], dp2[i][0], dp2[i][1]);
            }
            sta[0] = -INFLL;
    		TMP[1] = sta[1] = ar[1] - br[1];
    		ans = dp1[1][0];
    		dfs2(1, 0);//max minnum
    		printf("%lld
    ", ans);
        }
    #ifndef ONLINE_JUDGE
    //    cout << "time cost:" << 1.0*(clock())/CLOCKS_PER_SEC << "
    ";
    #endif
        return 0;
    }
    /*
    6
    7
    -1 -1 -1 0 1 1 1
    0 0 0 0 0 0 0
    1 2
    2 3
    3 4
    4 5
    5 6
    6 7
    5
    -100 1 -100 1 1
    0 0 0 0 0
    1 2
    1 3
    2 4
    2 5
    3
    1 1 1
    0 2 3
    1 2
    1 3
    5
    1 1 1 2 4
    0 2 3 3 2
    1 2
    1 3
    2 4
    2 5
    11
    1 1 1 2 4 4 3 2 5 6 2
    0 2 3 3 2 0 3 2 6 4 3
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    4 8
    4 9
    8 10
    8 11
    11
    2 4 5 3 6 8 1 0 6 4 3
    9 3 5 0 6 1 3 5 7 9 0
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    4 8
    4 9
    8 10
    8 11
    */
    
  • 相关阅读:
    Android 屏幕适配比例
    不错的网站
    Android十大常用技术揭秘-挑战
    Linux 自己的常用命令
    Android 常用配置
    Android 边框 给控件添加边框
    Linux 常用命令大全
    TCP/IP、Http、Socket的区别
    Android 之基于 HTTP 协议的通信详解
    JavaScript基础:(加号,数值转换,布尔转换)
  • 原文地址:https://www.cnblogs.com/Cwolf9/p/11346421.html
Copyright © 2011-2022 走看看