UVALive 7338 C - Toll Management IV


题目描述:
Another attempt of revising toll system is rejected by the people of Byteland. The Government is in big trouble now. They are seeking help of Hashmat, the brave warrior and the great programmer of Byteland to solve the problem. Hashmat has come up with a new idea to fix this toll management problem. There are N cities and M bidirectional highways among these cities. The government proposed some toll (may be different toll for different highways) for each of the highways. But people think they are being over charged. Hashmat’s idea was to make both the people and the Government happy. In his plan he decided to keep the toll of the highways as it is in Government’s proposal but he would publish a special set of N − 1 highways. There are two conditions for a set of N − 1 highways to be special. These N − 1 highways have to connect all the cities and a person will be able to go from a city to any other city spending minimum toll in any of these highways. Please note, using these special highways does not guarantee minimum sum of toll but it guarantees you minimum individual toll. People of Byteland are happy with the idea of special highway, but the Government is not happy as they want more toll from the highway sector. They called up a meeting and formed a committee to find two values for all the highways. Let these values be Ai and Bi for the i-th highway and defined as follows: 1) Ai
The maximum amount of toll they can add to the i-th highway so that Hashmat’s set remains
special.
2) Bi
The maximum amount of toll they can decrease from the i-th highway so that Hashmat’s set
remains special.
In other words, if Ci
is the current toll of the i-th highway, then if the Government updates the toll
of the highway to Ci + Ai (or Ci − Bi), Hashmat’s set remains special. Please note, while finding out
Ai and Bi other tolls remain unchanged.
This time Hashmat does not want to help the Government. He thinks this is a conspiracy against
the people of Byteland. So they came to you. Will you help them to find out Ai and Bi for all the
highways?
Input
First line of the input contains a positive integer T (T < 25), denoting the number of test cases.
First line of each test contains two integer numbers N and M (1 ≤ N ≤ 10000, N − 1 ≤ M ≤
100000), denoting the number of city and number of highway respectively. Each of the next M lines
contains the description of a highway, where the i-th line contains three integer numbers Ui
, Vi and Ci
(1 ≤ U i, V i ≤ N, U i ̸= V i, 0 ≤ Ci ≤ 1000), that means there is a highway between city Ui and city
Vi and the toll of the highway is Ci
. You may consider the highways to be bidirectional. Note that
the first N − 1 highways in the input are the special highways. You may assume that there will be no
invalid data in the input file.
Output
For each test case, output the test case number and a single integer S, where
S =

M
i=1
(i ∗ Ai + i
2
∗ Bi)
题解:

其实是一道很裸的题目. 唯一需要想的是,对于树边,它增大的时候需要考虑所有跨过它的非树边,那么反着想,就是所有非树边更新它这条链上的所有树边.之后就是边的树链剖分.

重点:

1.树边获取和用非树边更新的关系
2.边的树链剖分

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>

using namespace std;

typedef long long ll;
const int maxn = 10000 + 100;
const int MAXNODE = 4 * maxn + 100;
const int M = 10000;

struct edge {
    int to, w;
    edge(int _to = 0, int _w = 0) {
        to = _to;
        w = _w;
    }
};
vector<edge> G[maxn];
int n, deep[maxn], m;
int tp[maxn], fa[maxn], son[maxn], w[maxn], no[maxn], fanno[maxn], cnt;
int tree[MAXNODE], tag[MAXNODE];
int A[maxn * 10], B[maxn * 10];
int tu[maxn * 10], tv[maxn * 10], tw[maxn * 10];
int st[21][maxn], L2[maxn];

void st_initail() {
    for(int s = 1; s <= 20; s++) {
        for(int i = 1;i + (1 << s) - 1 <= cnt; i++) {
            int j = i + (1 << (s - 1));
            st[s][i] = max(st[s - 1][i], st[s - 1][j]);
        }
    }
}
int st_query(int l, int r) {
    int len = (r - l + 1);
    int s = L2[len];
    return max(st[s][l], st[s][r - (1 << s) + 1]);
}

void dfs1(int u, int pa) {
    w[u] = 1;
    son[u] = 0;
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i].to;
        if(v != pa) {
            deep[v] = deep[u] + 1;
            fa[v] = u;
            dfs1(v, u);
            w[u] += w[v];
            if(w[v] > w[son[u]])
                son[u] = v;
        }
    }
}
void dfs2(int u, int top) {
    tp[u] = top;
    cnt++;
    no[u] = cnt;
    fanno[cnt] = u;
    if(son[u] != 0) {
        dfs2(son[u], top);
    }
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i].to;
        if(v != fa[u] && v != son[u]) {
            dfs2(v, v);
        }
    }
}
 void dfs3(int u) {
     for(int i = 0; i < G[u].size(); i++) {
         int v = G[u][i].to, w = G[u][i].w;
         if(v != fa[u]) {
             st[0][no[v]] = w;
             dfs3(v);
         }
     }
 }

void initail(int rt, int l, int r) {
    //printf("aaa  %d %d %d\n", rt, l, r);
    tree[rt] = M;
    tag[rt] = M;
    if(l == r) {
        ;
    }
    else {
        int mid = (l + r) / 2;
        initail(rt * 2, l, mid);
        initail(rt * 2 + 1, mid +1, r);
    }
}

void pushDown(int rt) {
    if(tag[rt] == M)
        return;
    int lrt = 2 * rt, rrt = 2 * rt + 1;
    tag[lrt] = min(tag[lrt], tag[rt]);
    tag[rrt] = min(tag[rrt], tag[rt]);
    tree[lrt] = min(tree[lrt], tag[rt]);
    tree[rrt] = min(tree[rrt], tag[rt]);

    tag[rt] = M;
}
void pushUp(int rt) {
    int lrt = 2 * rt, rrt = 2 * rt + 1;
    tree[rt] = min(tree[lrt], tree[rrt]);
}

void update(int L, int R, int k, int rt, int l, int r) {
    //printf("ccc  %d %d %d\n", rt, l, r);
    if(L <= l && R >= r) {
        tag[rt] = min(tag[rt], k);
        tree[rt] = min(tree[rt], k);
        return;
    }
    pushDown(rt);
    int mid = (l + r) / 2, lrt = 2 * rt, rrt = lrt + 1;
    if(L <= mid) {
        update(L, R, k, lrt, l, mid);
    }
    if(R >= mid + 1) {
        update(L, R, k, rrt, mid + 1, r);
    }
    pushUp(rt);
}
int query(int pos, int rt, int l, int r) {
    if(l == r) {
        return tree[rt];
    }
    pushDown(rt);
    int mid = (l + r) / 2, lrt = 2 * rt, rrt = 2 * rt + 1;
    if(pos <= mid)
        return query(pos, lrt, l, mid);
    return query(pos, rrt, mid + 1, r);
}

void change(int u, int v, int k) {
    int tpu = tp[u], tpv = tp[v];
    while(tpu != tpv) {
        if(deep[tpu] < deep[tpv]) {
            swap(tpu, tpv);
            swap(u, v);
        }
        update(no[tpu], no[u], k, 1, 1, cnt);
        u = fa[tpu];
        tpu = tp[u];
    }
    if(u == v)
        return;
    if(deep[u] < deep[v]) {
        swap(u, v);
    }
    //printf("bbb %d %d %d\n", no[son[v]], no[u], k);
    update(no[son[v]], no[u], k, 1, 1, cnt);
}

 int queryMax(int u, int v) {
     int ans = 0;
     int tpu = tp[u], tpv = tp[v];
     while(tpu != tpv) {
         if(deep[tpu] < deep[tpv]) {
             swap(tpu, tpv);
             swap(u, v);
         }
         ans = max(ans, st_query(no[tpu], no[u]));
         u = fa[tpu];
         tpu = tp[u];
     }
     if(u == v)
         return ans;
     if(deep[u] < deep[v])
        swap(u, v);
     // printf("888 %d  %d\n", u, v);
     ans = max(ans, st_query(no[son[v]], no[u]));
     return ans;
 }

void solve() {
    memset(st[0], 0, sizeof(st[0]));
    memset(deep, 0, sizeof(deep));
    memset(w, 0, sizeof(w));
    dfs1(1, 0);
    //printf("%d %d %d\n", getLCA(2, 3), getLCA(2, 3), getLCA(1, 3));
    tp[1] = 1;
    cnt = 0;
    dfs2(1, 1);
    initail(1, 1, cnt);
    //printf("%d\n", cnt);
    dfs3(1);
    st_initail();
    //printf("777 %d %d\n", queryMax(1, 3), no[2]);
    for(int i = 0; i < m - (n - 1); i++) {
        int u, v, c;
        scanf("%d %d %d", &u, &v, &c);
        A[n - 1 + i] = -1;
        B[n - 1 + i] = c - queryMax(u, v);
        //printf("666 %d\n", B[n - 1 + i]);
        change(u, v, c);
    }
    for(int i = 0; i < n - 1; i++) {
        B[i] = -1;
        int t = tu[i];
        if(deep[tu[i]] > deep[tv[i]])
            t = tu[i];
        else
            t = tv[i];

        A[i] = query(no[t], 1, 1, cnt);
        if(A[i] == M) {
            A[i] = -1;
        }
        else {
            A[i] = A[i] - tw[i];
        }
    }
    ll ans = 0;
    for(int i = 0; i < m; i++) {
        //printf("ddd   %d  %d  %d\n", i, A[i], B[i]);
        ans = ans + (ll)(i + 1) * (ll)A[i] + (ll)(i + 1) * (ll)(i + 1) * (ll)B[i];
    }
    printf("%lld\n", ans);
}

int main() {
    //freopen("c.txt", "r", stdin);
    L2[0] = -1;
    for(int i = 1; i <= 10000; i++) {
        if((i & (i - 1)) == 0)
            L2[i] = L2[i - 1] + 1;
        else
            L2[i] = L2[i - 1];
    }
    int ncase;
    scanf("%d", &ncase);
    for(int _ = 1; _ <= ncase; _++) {
        printf("Case %d: ", _);
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            G[i].clear();
        for(int i = 0; i < n - 1; i++) {
            int u, v, c;
            scanf("%d%d%d", &u, &v, &c);
            G[u].push_back(edge(v, c));
            G[v].push_back(edge(u, c));
            tu[i] = u;
            tv[i] = v;
            tw[i] = c;
        }
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值