HDU-6393 Traffic Network in Numazu(基环树/树剖+树状数组)

Traffic Network in Numazu

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 200    Accepted Submission(s): 70

Problem Description

Chika is elected mayor of Numazu. She needs to manage the traffic in this city. To manage the traffic is too hard for her. So she needs your help. 
You are given the map of the city —— an undirected connected weighted graph with N nodes and N edges, and you have to finish Q missions. Each mission consists of 3 integers OP, X and Y. 
When OP=0, you need to modify the weight of the Xth edge to Y. 
When OP=1, you need to calculate the length of the shortest path from node X to node Y.

Input

The first line contains a single integer T, the number of test cases. 
Each test case starts with a line containing two integers N and Q, the number of nodes (and edges) and the number of queries. (3≤N≤105)(1≤Q≤105) 
Each of the following N lines contain the description of the edges. The ith line represents the ith edge, which contains 3 space-separated integers ui, vi, and wi. This means that there is an undirected edge between nodes ui and vi, with a weight of wi. (1≤ui,vi≤N)(1≤wi≤105) 
Then Q lines follow, the ith line contains 3 integers OP, X and Y. The meaning has been described above.(0≤OP≤1)(1≤X≤105)(1≤Y≤105) 
It is guaranteed that the graph contains no self loops or multiple edges.

Output

For each test case, and for each mission whose OP=1, print one line containing one integer, the length of the shortest path between X and Y.

Sample Input

2 5 5 1 2 3 2 3 5 2 4 5 2 5 1 4 3 3 0 1 5 1 3 2 1 5 4 0 5 4 1 5 1 5 3 1 2 3 1 3 2 3 4 4 4 5 5 2 5 5 0 1 3 0 4 1 1 1 4

Sample Output

5 6 6 6

传送门:HDU-6393

题意:有一个基环树,有两种操作:修改一条边的长度,查询两点间的最短路径

题解:可以看成一个环加上若干个树,分成两部分考虑,在树上用树剖维护,在环上用树状数组维护。

#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'
#define FIN freopen("in.txt","r",stdin);
#define eps 1e-8
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;

typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MX = 1e5 + 5;

struct Edge {
    int v, w, nxt;
} E[MX << 1];
int head[MX], tot, IN[MX];
bool vis[MX];
void init(int n) {
    rep(i, 1, n + 1) vis[i] = IN[i] = 0, head[i] = -1;
    tot = 0;
}
inline void edge_add(int u, int v, int w) {
    E[tot] = (Edge) {v, w, head[u]}, head[u] = tot++;
    IN[v]++;
}
int rt[MX];
struct Tree {
    int f[MX], p[MX], sz[MX], son[MX], top[MX], dep[MX], totp;
    ll sum[MX << 2], d[MX];
    void dfs(int u, int fa, int deep, int root) {
        f[u] = fa; dep[u] = deep;
        son[u] = 0; sz[u] = 1;
        rt[u] = root;
        for (int i = head[u]; ~i; i = E[i].nxt) {
            int v = E[i].v;
            if (v == fa || !vis[v]) continue;
            dfs(v, u, deep + 1, root);
            sz[u] += sz[v];
            if (sz[son[u]] < sz[v]) son[u] = v;
        }
    }
    void rebuild(int u, int t) {
        top[u] = t; p[u] = totp++;
        if (son[u]) rebuild(son[u], t);
        for (int i = head[u]; ~i; i = E[i].nxt) {
            int v = E[i].v;
            if (v == f[u] || !vis[v]) continue;
            if (v == son[u]) {
                d[p[v]] = E[i].w;
                continue;
            }
            rebuild(v, v);
            d[p[v]] = E[i].w;
        }
    }
    void prebuild(int n) {
        totp = 1;
        rep(i, 1, n + 1) if(!vis[i]) {
            dfs(i, 0, 1, i);
            rebuild(i, 1);
        }
        build(1, totp - 1, 1);
    }
    inline void PushUP(int rt) {
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    }
    void build(int l, int r, int rt) {
        if (l == r) {
            sum[rt] = d[l];
            return;
        }
        int m = (l + r) >> 1;
        build(lson), build(rson);
        PushUP(rt);
    }
    void update(int p, int c, int l, int r, int rt) {
        if (l == r) {
            sum[rt] = c;
            return;
        }
        int m = (l + r) >> 1;
        if (p <= m) update(p, c, lson);
        else update(p, c, rson);
        PushUP(rt);
    }
    ll query(int L, int R, int l, int r, int rt) {
        if (L <= l && R >= r) return sum[rt];
        int m = (l + r) >> 1;
        ll ret = 0;
        if (L <= m) ret += query(L, R, lson);
        if (R > m) ret += query(L, R, rson);
        return ret;
    }
    ll solve(int u, int v) {
        int f1 = top[u], f2 = top[v];
        ll ans = 0;
        while (f1 != f2) {
            if (dep[f1] < dep[f2]) {
                swap(f1, f2);
                swap(u, v);
            }
            ans += query(p[f1], p[u], 1, totp - 1, 1);
            u = f[f1]; f1 = top[u];
        }
        if (u != v) {
            if (dep[u] > dep[v]) swap(u, v);
            ans += query(p[son[u]], p[v], 1, totp - 1, 1);
        }
        return ans;
    }
    inline void Update(int u, int v, int val) {
        if(u == f[v]) swap(u, v);
        update(p[u], val, 1, totp - 1, 1);
    }
} t;
struct BitTree {
    int n;
    vector <ll> T;
    void init (int _n) {
        if (T.empty()) T.resize(MX);
        else for (int i = 0; i <= _n; i++) T[i] = 0;
        n = _n;
    }
    void add(int x, ll v) {
        for (int i = x; i <= n; i += i & -i) T[i] += v;
    }
    ll sum(int x) {
        if (x > n) x = n;
        ll ret = 0;
        for (int i = x; i > 0; i -= i & -i) ret += T[i];
        return ret;
    }
} bt;
int n, m;
PII edge[MX];
int ew[MX], dfn[MX], dfn_cnt, par;
bool mark[MX];
void search(int u, int pre) {
    dfn[u] = ++dfn_cnt;
    for(int i = head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v, w = E[i].w;
        if(v == pre || vis[v]) continue;
        bt.add(dfn[u], w);
        if(v == par) break;
        search(v, u);
        break;
    }
}
void pre_solve() {
    queue<int>q;
    rep(i, 1, n + 1) if(IN[i] == 1) q.push(i);
    while(!q.empty()) {
        int u = q.front(); q.pop();
        vis[u] = 1;
        for(int i = head[u]; ~i; i = E[i].nxt) {
            int v = E[i].v;
            IN[v]--;
            if(IN[v] == 1) q.push(v);
        }
    }
    t.prebuild(n);
    rep(i, 1, n + 1) if(!vis[edge[i].x] && !vis[edge[i].y]) mark[i] = 1;
    dfn_cnt = 0, bt.init(n);
    rep(i, 1, n + 1) if(!vis[i]) {par = i; search(i, i); break;}
}

int main() {
#ifdef local
    FIN;
#endif
    int cas; cin >> cas;
    while (cas--) {
        scanf("%d%d", &n, &m);
        init(n);
        int u, v, w;
        rep(i, 1, n + 1) {
            scanf("%d%d%d", &u, &v, &w);
            edge_add(u, v, w);
            edge_add(v, u, w);
            edge[i] = PII(u, v);
            mark[i] = 0;
            ew[i] = w;
        }
        pre_solve();
        int op, x, y;
        rep(i, 0, m) {
            scanf("%d%d%d", &op, &x, &y);
            if(op == 0) {
                u = edge[x].x, v = edge[x].y;
                if(mark[x]) {
                    if(dfn[u] > dfn[v]) swap(u, v);
                    if(dfn[u] == 1 && dfn[v] == dfn_cnt) bt.add(dfn[v], y - ew[x]);
                    else bt.add(dfn[u], y - ew[x]);
                    ew[x] = y;
                } else t.Update(u, v, y);
            } else {
                if(rt[x] == rt[y]) printf("%lld\n", t.solve(x, y));
                else {
                    ll ans = 0;
                    if(x != rt[x]) ans += t.solve(x, rt[x]);
                    if(y != rt[y]) ans += t.solve(y, rt[y]);
                    x = rt[x], y = rt[y];
                    if(dfn[x] > dfn[y]) swap(x, y);
                    ll tmp = bt.sum(dfn[y] - 1) - bt.sum(dfn[x] - 1);
                    tmp = min(tmp, bt.sum(dfn_cnt) - tmp);
                    printf("%lld\n", ans + tmp);
                }
            }
        }
    }
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值