codeforces 733F (树链剖分 RMQ)

来源:互联网 发布:java外包公司怎么找 编辑:程序博客网 时间:2024/05/29 15:18

题目链接:点击这里

题意:给出一个图,每条边有权值和花费c,每次花费c能使的权值-1。给出一个预算,求减完权值后的一个最小生成树。

观察到最优的策略必然是只减少一条边的权值。于是首先先将初始权值做一次最小生成树。然后枚举所有的边,如果这条边是生成树的边,求出预算都花在这条边上的结果;如果非树边,就在这条边两个点到他们的LCA路径上求出树边的最大值,这个最大值用轻重链剖分维护,(也可以往上倍增)树链上无修改的最大值可以用RMQ维护,然后求出扣掉这个最大树边,加进去这条边的最终结果。中间过程维护一下最小值。

#include <bits/stdc++.h>using namespace std;#define Clear(x,y) memset (x,y,sizeof(x));#define maxn 200005#define maxm maxn<<1int n, m;long long w[maxn], c[maxn], S;struct E {    int u, v, id;    bool operator < (const E &a) const {        return w[id] < w[a.id];    }}e[maxn];bool in_mst[maxn];//每条边在不在mst中struct node {    int v, next, id;}edge[maxm];int head[maxn], cnt;int top[maxn], fa[maxn], deep[maxn], num[maxn], p[maxn], fp[maxn];int son[maxn], pos;long long MST;void add_edge (int u, int v, int id) {    edge[cnt].id = id;    edge[cnt].v = v, edge[cnt].next = head[u], head[u] = cnt++;}int Find (int x) {return fa[x] == x ? fa[x] : fa[x] = Find (fa[x]);}void init () {    MST = 0;    Clear (in_mst, 0);    Clear (head, -1);    cnt = 0;    for (int i = 1; i <= n; i++) fa[i] = i;    for (int i = 1; i <= m; i++) {// cout << e[i].id << " ";        int p1 = Find (e[i].u), p2 = Find (e[i].v);        if (p1 != p2) {            fa[p1] = p2;            MST += w[e[i].id];            in_mst[e[i].id] = 1;            add_edge (e[i].u, e[i].v, e[i].id);            add_edge (e[i].v, e[i].u, e[i].id);        }    } //cout << endl;    Clear (son, -1);    pos = 0;    //for (int i = 1; i <= m; i++) if (in_mst[i]) cout << i << " "; cout << endl;    //cout << MST << endl;}void dfs1 (int u, int pre, int d) {    deep[u] = d;    fa[u] = pre;    num[u] = 1;    for (int i = head[u]; i != -1; i = edge[i].next) {        int v = edge[i].v;        if (v == pre) continue;        dfs1 (v, u, d+1);        num[u] += num[v];        if (son[u] == -1 || num[v] > num[son[u]]) son[u] = v;    }}#define pii pair<long long, int>#define mp make_pairpii dp[maxn][20];pii min (pii a, pii b) {    return a < b ? a : b;}pii max (pii a, pii b) {    return a < b ? b : a;}void getpos (int u, int sp) {    top[u] = sp;    p[u] = pos++;    fp[p[u]] = u;    if (son[u] == -1) return ;    getpos (son[u], sp);    for (int i = head[u]; i != -1; i = edge[i].next) {        int v = edge[i].v;        if (v == fa[u] || v == son[u]) continue;        getpos (v, v);    }}void dfs2 (int u) {    for (int i = head[u]; i != -1; i = edge[i].next) {        int v = edge[i].v; if (v == fa[u]) continue;        dp[p[v]][0] = mp (w[edge[i].id], edge[i].id);        dfs2 (v);    }}void rmq_init () {    dfs2 (1);    for (int j = 1; (1<<j) <= n; j++) {        for (int i = 0; i+(1<<j)-1 < n; i++) {            dp[i][j] = max (dp[i][j-1], dp[i+(1<<(j-1))][j-1]);        }    }}pii rmq (int l, int r) {    int k = 0;    while ((1<<(k+1)) <= r-l+1) k++;    return max (dp[l][k], dp[r-(1<<k)+1][k]);}pii query (int u, int v) {    int f1 = top[u], f2 = top[v];    pii tmp = mp (0, 0);    while (f1 != f2) {        if (deep[f1] < deep[f2]) {            swap (u, v);            swap (f1, f2);        }        tmp = max (tmp, rmq (p[f1], p[u]));        u = fa[f1]; f1 = top[u];    }    if (u == v) return tmp;    if (deep[u] > deep[v]) swap (u, v);    return max (tmp, rmq (p[son[u]], p[v]));}void solve () {    dfs1 (1, 0, 0);    getpos (1, 1);    rmq_init ();    long long ans = 1e15; int pos = -1, del = -1;    for (int i = 1; i <= m; i++) {        long long tmp;        if (in_mst[e[i].id]) {            tmp = MST-S/c[e[i].id];            if (tmp < ans) {                ans = tmp;                pos = e[i].id;            }        }        else {            pii Min = query (e[i].u, e[i].v);            tmp = MST-w[Min.second]+w[e[i].id]-S/c[e[i].id];            if (tmp < ans) {                ans = tmp;                pos = e[i].id;                del = Min.second;            }        }    }    cout << ans << "\n";    for (int i = 1; i <= m; i++) if (in_mst[i] || i == pos) {        if (i == del) continue;        cout << i << " ";        if (i == pos) cout << w[i]-S/c[i] << "\n";        else cout << w[i] << "\n";    }}int main () {    //freopen ("more.in", "r", stdin);    ios::sync_with_stdio (0);    cin >> n >> m;    for (int i = 1; i <= m; i++) cin >> w[i];    for (int i = 1; i <= m; i++) cin >> c[i];    for (int i = 1; i <= m; i++) {        cin >> e[i].u >> e[i].v;        e[i].id = i;    }    cin >> S;    sort (e+1, e+1+m);    init ();    solve ();    return 0;}
0 0