Topcoder SRM 720 Hard

来源:互联网 发布:易语言软件自动更新 编辑:程序博客网 时间:2024/05/29 18:55

链接:

link

题意:

给一个图和两棵树,你要让第一棵树是最小生成树,第二棵树是最大生成树,改变的边权之和最小。

题解:

网络流。
首先可以很容易地转化为一个一般性问题:
记新边权为w,旧边权为v,有一些形如限制wiwj的限制,使|wivi|最小。
fi(x)=|xvi|fi(x)=fi(x)fi(x1),注意到fi(x)是不降的。
考虑对于一个给定的x,如何求出在最优解中哪些边的边权不超过x
将每个边变成网络流上的一个点,点权为fi(x),同时如果wiwj,就从ij连一条边。
求出一个最小权闭合子图记为C,那么C中的点最终的w会大于等于x
下面给出证明:
假设存在DC,同时D中的点在最优解中小于x,注意到一定不会有CDD的边,这意味着CD也是一个闭合子图。
由于C是最小权闭合子图,所以val(D)0,由于fi(x)不降,所以将D的权值改为x不会劣。
最后实际上是logmax(vi)次网络流的复杂度。

代码:

 #include <bits/stdc++.h>#define xx first#define yy second#define mp make_pair#define pb push_back#define mset(x, y) memset(x, y, sizeof x)#define mcpy(x, y) memcpy(x, y, sizeof x)using namespace std;typedef long long LL;typedef pair <int, int> pii;const int MAXN = 1005;const int MAXM = 200005;const int INF = 0x3f3f3f3f;bool edg[MAXN][MAXN], tag[MAXN], chosen[MAXN];int n, m, ql, qr, q[MAXN], dep[MAXN], w[MAXN];vector <pii> adj[MAXN];pii par[MAXN];LL ans;inline void Dfs(int x){    for (auto e : adj[x])        if (e.xx ^ par[x].xx)            par[e.xx] = mp(x, e.yy), dep[e.xx] = dep[x] + 1, Dfs(e.xx);}inline void Add(int x, int y, int i, bool t){    if (x == y)        return ;    if (dep[x] < dep[y])    {        if (!t)            edg[par[y].yy][i] = 1;        else            edg[i][par[y].yy] = 1;        Add(x, par[y].xx, i, t);    }    else    {        if (!t)            edg[par[x].yy][i] = 1;        else            edg[i][par[x].yy] = 1;        Add(par[x].xx, y, i, t);    }}namespace Flow{    struct Edge    {        int p, v, w;    } e[MAXM << 3];    int e_cnt, S, T, V, ql, qr, q[MAXN], hed[MAXN], dis[MAXN], cur[MAXN];    inline void Init(int n)    {        V = n;        for (int i = 0; i < V; i ++)            hed[i] = 0;        e_cnt = 1;    }    inline void Addedge(int x, int y, int w)    {        e[++ e_cnt] = {y, hed[x], w}; hed[x] = e_cnt;        e[++ e_cnt] = {x, hed[y], 0}; hed[y] = e_cnt;    }    inline bool Bfs()    {        for (int i = 0; i < V; i ++)            dis[i] = 0;        dis[q[ql = 0] = S] = qr = 1;        while (ql ^ qr)        {            int x = q[ql ++];            for (int i = hed[x]; i; i = e[i].v)                if (e[i].w && !dis[e[i].p])                    dis[q[qr ++] = e[i].p] = dis[x] + 1;        }        return dis[T];    }    inline int Dfs(int x, int f)    {        if (x == T)            return f;        int ret = 0, t = 0;        for (int &i = cur[x]; i; i = e[i].v)            if (e[i].w && dis[e[i].p] == dis[x] + 1)            {                t = Dfs(e[i].p, min(f, e[i].w));                f -= t; ret += t; e[i].w -= t; e[i ^ 1].w += t;                if (!f)                    return ret;            }        return dis[x] = -1, ret;    }    inline int Dinic()    {        int ret = 0;        while (Bfs())        {            for (int i = 0; i < V; i ++)                cur[i] = hed[i];            ret += Dfs(S, INF);        }        return ret;    }}inline void Solve(int l, int r, vector <int> &cur){    if (cur.size() == 0)        return ;    if (cur.size() == 1)    {        if (w[cur[0]] < l)            ans += l - w[cur[0]];        if (w[cur[0]] > r)            ans += w[cur[0]] - r;        return ;    }    if (l == r)    {        for (auto x : cur)            ans += abs(w[x] - l);        return ;    }    int n = cur.size(), mid = l + r >> 1;    Flow::Init(n + 2);    Flow::S = n, Flow::T = n + 1;    for (int i = 0; i < cur.size(); i ++)        if (w[cur[i]] > mid)            Flow::Addedge(Flow::S, i, 1);        else            Flow::Addedge(i, Flow::T, 1);    for (int i = 0; i < cur.size(); i ++)        for (int j = 0; j < cur.size(); j ++)            if (edg[cur[i]][cur[j]])                Flow::Addedge(i, j, INF);    Flow::Dinic();    for (int i = 0; i < n; i ++)        chosen[i] = Flow::dis[i];    vector <int> p, q;    for (int i = 0; i < n; i ++)        if (chosen[i])            p.pb(cur[i]);        else            q.pb(cur[i]);    Solve(l, mid, q);    Solve(mid + 1, r, p);}class ExtremeSpanningTrees{    public:        LL minTime(vector <int> a, vector <int> b, vector <int> w, vector <int> m1, vector <int> m2)         {            n = m1.size() + 1, m = a.size(), ans = 0;            mset(edg, 0);            for (int i = 0; i < m; i ++)                ::w[i] = w[i];            for (int i = 0; i < n; i ++)                adj[i].clear();            for (int i = 0; i < m; i ++)                tag[i] = 0;            for (int i = 0, u, v; i < n - 1; i ++)                u = a[m1[i]], v = b[m1[i]], adj[u].pb(mp(v, m1[i])), adj[v].pb(mp(u, m1[i])), tag[m1[i]] = 1;            par[0] = mp(-1, -1);            Dfs(0);            for (int i = 0; i < m; i ++)                if (!tag[i])                    Add(a[i], b[i], i, 0);            for (int i = 0; i < n; i ++)                adj[i].clear();            for (int i = 0; i < m; i ++)                tag[i] = 0;            for (int i = 0, u, v; i < n - 1; i ++)                u = a[m2[i]], v = b[m2[i]], adj[u].pb(mp(v, m2[i])), adj[v].pb(mp(u, m2[i])), tag[m2[i]] = 1;            par[0] = mp(-1, -1);            Dfs(0);            for (int i = 0; i < m; i ++)                if (!tag[i])                    Add(a[i], b[i], i, 1);            vector <int> cur;            int l = w[0], r = w[0];            for (int i = 0; i < m; i ++)                cur.pb(i), l = min(l, w[i]), r = max(r, w[i]);            Solve(l, r, cur);            return ans;        }};
原创粉丝点击