[CF Round603 Div2 F]Economic Difficulties

题目:Economic Difficulties

传送门:https://codeforces.com/contest/1263/problem/F

题意:给了两棵tree:Ta(拥有a个节点,节点编号为[n+1, n+a]) Tb(拥有b个节点, 节点编号: [n+ a + 1, n + a + b]) 其中两颗tree的叶子节点按照dfs序依次连续连向 $ i, i in [1, n] $节点,询问最多可以去掉多少的tree上节点,使得每一个$i , i in [1, n]$ 仍然可以连通Ta,或者Tb的根节点。

分析:

1.做法一:https://codeforces.com/blog/entry/71844?locale=en

类似泛化背包,每个物品要么选择a,要么选择b,连续选择有额外贡献,假设cost_a[i,j]代表[i,j]区间选择a的贡献,cost_b[i,j]代表[i,j]区间选择b的贡献。

dp[i]代表前i个节点,方程:$$ dp[i] = max{dp[j] + cost[j+1,i] }$$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 vector< vector<int> > calc_cost(int vn, int n, vector<int> fa, vector<int> tg) {
 5     vector< vector<int> > res(n+1, vector<int>(n+1));
 6     for (int l = 1; l <= n; l++) {
 7         vector<int> deg(vn+1);
 8         for (int i = 2; i <= vn ; i++) deg[fa[i]]++;
 9         int val = 0;
10         for (int r = l; r <= n; r++) {
11             for(int v = tg[r]; v != 1 && deg[v] == 0; --deg[v = fa[v]]) 
12                 val++;
13             res[l][r] = val;
14         }
15     }
16     return res;
17 }
18 
19 int main() {
20     int n;
21     scanf("%d", &n);
22     vector< vector<int> > cost[2];
23     for (int j = 0; j < 2; j++) {
24         int vn;
25         scanf("%d", &vn);
26         vector<int> fa(vn+1);
27         vector<int> tg(n+1);
28         for (int i = 2; i <= vn; i++) scanf("%d", &fa[i]);
29         for (int i = 1; i <= n;  i++)  scanf("%d", &tg[i]);
30         cost[j] = calc_cost(vn, n, fa, tg);
31     }
32     
33     vector<int> dp(n + 1, 0);
34     for (int i = 1; i <= n; i++) 
35         for (int j = 0; j < i; j++) 
36             dp[i] = max(dp[i], dp[j] + max(cost[0][j+1][i], cost[1][j+1][i]));
37     printf("%d", dp[n]);
38     return 0;
39 }
View Code

2.基于最后的结果,我们肯定是选择Ta和Tb的一些节点,去除这些节点及其后代节点,考虑到这里,我们只要把每个节点控制的区间算出来,然后按照左端点或者有端点排序,然后做限制背包dp。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e4 + 7;
const int INF = 1e9 + 7;
vector< pair<pair<int,int>, int> > vec;
int sz[MAXN], st[MAXN], ed[MAXN], tg[MAXN];
vector<int> G[MAXN];
void dfs(int u) {
    sz[u] = 1;
    st[u] = INF; ed[u] = -INF;
    if(tg[u]) st[u] = ed[u] = tg[u];
    for(auto v : G[u]) {
        dfs(v);
        sz[u] += sz[v];
        st[u] = min(st[u], st[v]);
        ed[u] = max(ed[u], ed[v]);
    }
    vec.push_back(make_pair(make_pair(ed[u], st[u] - 1), sz[u]-(u == 1)));
}
int dp[MAXN];
int main() {
    int n, a, x;
    scanf("%d", &n);
    for(int j = 0; j < 2; j++) { 
        scanf("%d", &a);
        for(int i = 2;i <= a; i++) {
            scanf("%d", &x);
            G[x].push_back(i);
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d", &x);
            tg[x] = i;
        }
        dfs(1);
        for(int i = 1; i <= a; i++) {
            G[i].clear();
            tg[i] = 0;
        }
    }
    sort(vec.begin(), vec.end());
    for(auto it : vec) {
        int l = it.first.second, r = it.first.first;
        dp[r] = max(dp[r], dp[l] + it.second);
    }
    printf("%d", dp[n]);
    return 0;
}

3.和文理分科类似,该题也可以用网络流求解,然而我到现在都不知道为啥是对的。

#include <bits/stdc++.h>
using namespace std;
typedef int LL;
const int MAXN = 1e5 + 7;
const int MAXM = 1e5 + 7;
const int INF = 1e9 + 7;

namespace NWF {
    struct Edge {
        int to, nxt;LL f;
    } e[MAXM << 1]; 
    int S, T, tot;
    int ecnt, head[MAXN], cur[MAXN], dis[MAXN];
    queue<int> q;
    void init(int _S, int _T, int _tot){
        ecnt = 1; S = _S; T = _T; tot = _tot;
        memset(head, 0, (tot + 1) * sizeof(int));
    } 
    void addEdge(int u, int v, LL f) {
        e[++ecnt] = (Edge) {v, head[u], f}; head[u] = ecnt;
        e[++ecnt] = (Edge) {u, head[v], 0}; head[v] = ecnt;
    }
    bool bfs() {
        memset(dis, 0, (tot + 1) * sizeof(int));
        q.push(S); dis[S] = 1;
        while (!q.empty()) {
            int u = q.front(), v; q.pop();
            for (int i = cur[u] = head[u]; i ; i = e[i].nxt) {
                if (e[i].f && !dis[v = e[i].to]) {
                    q.push(v);
                    dis[v] = dis[u] + 1;
                }
            }
        }
        return dis[T];
    }
    LL dfs(int u, LL maxf) {
        if (u == T) return maxf;
        LL sumf = maxf;
        for (int &i = cur[u]; i; i = e[i].nxt) {
            if (e[i].f && dis[e[i].to] > dis[u]) {
                LL tmpf = dfs(e[i].to, min(sumf, e[i].f));
                e[i].f -= tmpf; e[i ^ 1].f += tmpf;
                sumf -= tmpf;
                if (!sumf) return maxf;
            }
        }
        return maxf - sumf;
    }
    LL dinic() {
        LL ret = 0;
        while (bfs()) ret += dfs(S, INF);
        return ret;
    }
}
int faa[MAXN], fab[MAXN], tga[MAXN], tgb[MAXN];
int main() {
    int n, A, B;
    scanf("%d", &n);
    scanf("%d", &A);
    for(int i = 2;i <= A; i++) scanf("%d", faa+i);
    for(int i = 1; i <= n; i++) scanf("%d", tga + i);
    scanf("%d", &B);
    for(int i = 2;i <= B; i++) scanf("%d", fab+i);
    for(int i = 1; i <= n; i++) scanf("%d", tgb + i);
        
    NWF::init(A+B+1,A+B+2, A+B+3);
    for (int i = 2; i <= A; i++) {
        NWF::addEdge(NWF::S, i, 1);
        NWF::addEdge(faa[i], i, INF);
    }
    for (int i = 2; i <= B; i++) {
        NWF::addEdge(A + i, A + fab[i], INF);
        NWF::addEdge(A + i, NWF::T, 1);
    }
    for (int i = 1; i <= n; i++)
        NWF::addEdge(tga[i], A + tgb[i], INF);
        
    int ans = A - 1 + B - 1 - NWF::dinic();
    printf("%d", ans);
    return 0;
}
View Code
#include <bits/stdc++.h>
using namespace std;
typedef int LL;
const int MAXN = 1e5 + 7;
const int MAXM = 1e5 + 7;
const int INF = 1e9 + 7;

namespace NWF {
    struct Edge{
        int to, nxt;LL f;
    }e[MAXM << 1];
    int S, T, tot;
    int ecnt, head[MAXN], cur[MAXN], pre[MAXN], num[MAXN], dis[MAXN];
    queue<int> q;
    void init(int _S, int _T, int _tot){
        ecnt = 1; S = _S; T = _T; tot = _tot;
        memset(num,  0, (tot + 1) * sizeof(int));
        memset(head, 0, (tot + 1) * sizeof(int));
    } 
    inline void addEdge(int u, int v, LL f) {
        e[++ecnt] = (Edge) {v, head[u], f}; head[u] = ecnt;
        e[++ecnt] = (Edge) {u, head[v], 0}; head[v] = ecnt;
    }
    void bfs() {
        memset(dis, 0, (tot + 1) * sizeof(int));
        q.push(T);
        dis[T] = 1;
        while(!q.empty()) {
            int u = q.front(), v; q.pop();
            num[dis[u]]++;
            for(int i = cur[u] = head[u]; i; i = e[i].nxt) {
                if(!dis[v = e[i].to]) {
                    dis[v] = dis[u] + 1;
                    q.push(v);
                }
            }
        }
    }
    LL augment() {
        LL flow = INF;
        for(int i = S; i != T; i = e[cur[i]].to) 
            flow = min(flow, e[cur[i]].f);
        for(int i = S; i != T; i = e[cur[i]].to) {
            e[cur[i]].f -= flow;
            e[cur[i] ^ 1].f += flow;
        }
        return flow;
    }
    LL isap() {
        bfs();
        int u = S, v;
        LL flow = 0;
        while(dis[S] <= tot) {
            if(u == T) {
                flow += augment();
                u = S;
            }
            bool fg = 0;
            for(int i = cur[u]; i; i = e[i].nxt) {
                if(e[i].f && dis[u] > dis[v = e[i].to]) {
                    pre[v] = u;
                    cur[u] = i;
                    u = v;
                    fg = 1;
                    break;
                }
            }
            if(fg) continue;
            if(!--num[dis[u]]) break;
            int maxDis = tot;
            for(int i = head[u]; i; i = e[i].nxt) {
                if(e[i].f && maxDis > dis[v = e[i].to]) {
                    maxDis = dis[v];
                    cur[u] = i;
                }
            }
            num[dis[u] = maxDis + 1]++;
            if(u != S) u = pre[u];
        }
        return flow;
    }
}
int faa[MAXN], fab[MAXN], tga[MAXN], tgb[MAXN];
int main() {
    int n, A, B;
    scanf("%d", &n);
    scanf("%d", &A);
    for(int i = 2;i <= A; i++) scanf("%d", faa+i);
    for(int i = 1; i <= n; i++) scanf("%d", tga + i);
    scanf("%d", &B);
    for(int i = 2;i <= B; i++) scanf("%d", fab+i);
    for(int i = 1; i <= n; i++) scanf("%d", tgb + i);
        
    NWF::init(A+B+1,A+B+2, A+B+3);
    for (int i = 2; i <= A; i++) {
        NWF::addEdge(NWF::S, i, 1);
        NWF::addEdge(faa[i], i, INF);
    }
    for (int i = 2; i <= B; i++) {
        NWF::addEdge(A + i, A + fab[i], INF);
        NWF::addEdge(A + i, NWF::T, 1);
    }
    for (int i = 1; i <= n; i++)
        NWF::addEdge(tga[i], A + tgb[i], INF);
        
    int ans = A - 1 + B - 1 - NWF::isap();
    printf("%d", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/hjj1871984569/p/11973734.html