• Traffic Network in Numazu HDU


    Traffic Network in Numazu (HDU - 6393)

    题意:给定一张(n)个点(n)条边的带权图。要求支持两种操作:

    • (0 x y :)修改第(x)条边的权值为(y)
    • (1 x y :)查询((x,y))的最短路。

    题解:

    (n)个点(n)条边,就是一颗基环树。我们可以拆掉基环树上的一条边,变为一棵树。那么两个点的最短路就是树上的距离和经过拆掉的边的距离,取最小值。

    对于树上的距离,我们可以用线段树维护每个点到根节点的距离来求出。每次修改一条边的权值时,就把这条边以下的子树整体修改。

    对于((x,y))经过被拆掉的边((u,v,len))的情况,我们可以在((x, u)+(y, v)+len)((x,v)+(y,u)+len)(min)

    最后把上面两种情况取(min)就是询问的答案。

    代码:

    #include <bits/stdc++.h>
    #define fopi freopen("in.txt", "r", stdin)
    #define fopo freopen("out.txt", "w", stdout)
    using namespace std;
    typedef long long LL;
    typedef pair<int, LL> Pair;
    const int inf = 0x3f3f3f3f;
    const int maxn = 1e5 + 10;
    
    LL d[maxn];
    struct SegTree {
        struct Node {
            int l, r;
    		LL sum, add;
        }t[maxn*4];
    
        void build(int id, int l, int r) {
            t[id].l = l, t[id].r = r;
            t[id].add = 0;
            if (l == r) {
                t[id].sum = d[t[id].l];
                return;
            }
            int mid = (l+r) / 2;
            build(id*2, l, mid);
            build(id*2+1, mid+1, r);
            t[id].sum = t[id*2].sum + t[id*2+1].sum;
        }
    
    	void pushdown(int id) {
    		if (t[id].add != 0) {
    			t[id*2].add += t[id].add;
    			t[id*2+1].add += t[id].add;
    			int mid = (t[id].l + t[id].r) / 2;
    			t[id*2].sum += t[id].add * (mid-t[id].l+1);
    			t[id*2+1].sum += t[id].add * (t[id].r-mid);
    			t[id].add = 0;
    		}
    	}
    
    	void update(int id, int l, int r, LL val) {
    		if (l <= t[id].l && r >= t[id].r) {
    			t[id].add += val;
    			t[id].sum += val * (t[id].r-t[id].l+1);
    			return;
    		}
    		pushdown(id);
    		int mid = (t[id].l + t[id].r) / 2;
    		if (r <= mid) update(id*2, l, r, val);
    		else if (l > mid) update(id*2+1, l, r, val);
    		else update(id*2, l, mid, val), update(id*2+1, mid+1, r, val);
    		t[id].sum = t[id*2].sum + t[id*2+1].sum;
    	}
    
    	LL query(int id, int x) {
    		if (t[id].l == x && t[id].r == x) return t[id].sum;
    		pushdown(id);
    		int mid = (t[id].l + t[id].r) / 2;
    		if (x <= mid) query(id*2, x); else query(id*2+1, x);
    	}
    }ST;
    
    int fa[maxn][22], dep[maxn], dfn[maxn], dfr[maxn];
    vector<Pair> V[maxn];
    int depth, tot;
    
    void init_lca(int x, int from) {
    	dfn[x] = ++tot;
    	dep[x] = dep[from] + 1;
    	for (auto p : V[x]) {
            int y = p.first, l = p.second;
            if (y == from) continue;
    		fa[y][0] = x;
    		for (int j = 1; j <= depth; j++)
    			fa[y][j] = fa[fa[y][j-1]][j-1];
    		init_lca(y, x);
    	}
    	dfr[x] = tot;
    }
    
    void dfs(int x, int from) {
        for (auto p : V[x]) {
            int y = p.first, l = p.second;
            if (y == from) continue;
            d[dfn[y]] = d[dfn[x]] + l;
            dfs(y, x);
        }
    }
    
    int lca(int x, int y) {
    	if (dep[x] > dep[y]) swap(x, y);
    	for (int i = depth; i >= 0; i--)
    		if (dep[fa[y][i]] >= dep[x]) y = fa[y][i];
    	if (x == y) return x;
    	for (int i = depth; i >= 0; i--)
    		if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
    	return fa[x][0];
    }
    
    LL dist(int x, int y) {
    	int L = lca(x, y);
    	LL d1 = ST.query(1, dfn[x]), d2 = ST.query(1, dfn[y]), d3 = ST.query(1, dfn[L]);
    	return d1 + d2 - 2 * d3;
    }
    
    int T, n, m;
    LL z[maxn];
    int y[maxn];
    int main() {
        scanf("%d", &T);
        for (int ca = 1; ca <= T; ca++) {
    		scanf("%d%d", &n, &m);
    		for (int i = 1; i <= n; i++) V[i].clear();
    
    		for (int i = 1; i <= n-1; i++) {
                int x;
    			scanf("%d%d%d", &x, &y[i], &z[i]);
    			//其实这里应该按照dep的深度存第i条边的儿子节点。
    			//所幸题目中没有逆序边,我也没wa。
    			V[x].push_back({y[i], z[i]});
    			V[y[i]].push_back({x, z[i]});
    		}
    		int xn, yn;
    		scanf("%d%d%d", &xn, &yn, &z[n]);
    
    		depth = 20, tot = 0;
    		init_lca(1, 0);
    		dfs(1, 0);
    		ST.build(1, 1, n);
    		for (int i = 1; i <= m; i++) {
    			int op, x, val;
    			scanf("%d%d%d", &op, &x, &val);
    			if (op == 0) {
    				if (x == n) { z[n] = val; continue; }
    				LL deta = val - z[x];
    				ST.update(1, dfn[y[x]], dfr[y[x]], deta);
    				z[x] = val;
    			}
    			else {
                    int fx = dfn[x], fy = dfn[val];
    				LL d1 = dist(x, val),
    					d2 = dist(x, xn) + dist(val, yn) + z[n],
    					d3 = dist(x, yn) + dist(val, xn) + z[n];
    				printf("%lld
    ", min(d1, min(d2, d3)));
    			}
    		}
    	}
    }
    
    
  • 相关阅读:
    tuple 元组及字典dict
    day 49 css属性补充浮动 属性定位 抽屉作业
    day48 选择器(基本、层级 、属性) css属性
    day47 列表 表单 css初识
    day 46 http和html
    day 45索引
    day 44 练习题讲解 多表查询
    day 40 多表查询 子查询
    day39 表之间的关联关系、 补充 表操作总结 where 、group by、
    day38 数据类型 约束条件
  • 原文地址:https://www.cnblogs.com/ruthank/p/11369306.html
Copyright © 2020-2023  润新知