FZU2082 过路费(树链剖分,边建树)

Problem Description

有n座城市,由n-1条路相连通,使得任意两座城市之间可达。每条路有过路费,要交过路费才能通过。每条路的过路费经常会更新,现问你,当前情况下,从城市a到城市b最少要花多少过路费。

Input

有多组样例,每组样例第一行输入两个正整数n,m(2 <= n<=50000,1<=m <= 50000),接下来n-1行,每行3个正整数a
b c,(1 <= a,b <= n , a != b , 1 <= c <=
1000000000).数据保证给的路使得任意两座城市互相可达。接下来输入m行,表示m个操作,操作有两种:一. 0 a
b,表示更新第a条路的过路费为b,1 <= a <= n-1 ; 二. 1 a b , 表示询问a到b最少要花多少过路费。

Output

对于每个询问,输出一行,表示最少要花的过路费。

Sample Input

2 3
1 2 1
1 1 2
0 1 2
1 2 1

Sample Output

1
2

思路

以前做树链剖分都是点有取值,这一题是边有权值,我们在处理的时候,对于每一条边的权值,可以把这个权值赋值给比深度比较大的点上。这样就可以把边权改为点权,更容易维护.

这个题令我RE了很久,最后debug成功后发现是int改成long long 造成的re,不知道原因。。
还有一点是w[id[e[i].u]] = e[i].w;要注意一下

代码

#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <sstream>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
#include <list>
using namespace std;
#define mem(a, b) memset(a, b, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
int first[N], tot, n, m;
int sum[N << 2];
int w[N], cnt, siz[N], dep[N], fa[N], son[N], top[N], id[N];
struct edge
{
    int u, v, w, next;
} e[N];
void add_edge(int u, int v, int w)
{
    e[tot].u = u, e[tot].v = v, e[tot].w = w;
    e[tot].next = first[u];
    first[u] = tot++;
}
void init()
{
    mem(first, -1);
    mem(w, 0);
    tot = 0;
    cnt = 0;
}
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] = w[l];
        return;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int p, int sc, int l, int r, int rt)
{
    if (l == r)
    {
        sum[rt] = sc;
        return;
    }
    int m = (l + r) >> 1;
    if (p <= m)
        update(p, sc, lson);
    else
        update(p, sc, rson);
    pushup(rt);
}
int query(int L, int R, int l, int r, int rt)
{
    if (L <= l && r <= R)
        return sum[rt];
    int m = (l + r) >> 1;
    int ans = 0;
    if (L <= m)
        ans += query(L, R, lson);
    if (R > m)
        ans += query(L, R, rson);
    pushup(rt);
    return ans;
}
void dfs1(int u, int f, int deep)
{
    siz[u] = 1;
    dep[u] = deep;
    fa[u] = f;
    son[u] = 0;
    int maxson = -1;
    for (int i = first[u]; ~i; i = e[i].next)
    {
        int v = e[i].v;
        if (v == f)
            continue;
        dfs1(v, u, deep + 1);
        siz[u] += siz[v];
        if (siz[v] > maxson)
        {
            son[u] = v;
            maxson = siz[v];
        }
    }
}
void dfs2(int u, int topf)
{
    top[u] = topf;
    id[u] = ++cnt;
    if (!son[u])
        return;
    dfs2(son[u], topf);
    for (int i = first[u]; ~i; i = e[i].next)
    {
        int v = e[i].v;
        if (v == fa[u] || v == son[u])
            continue;
        dfs2(v, v);
    }
}
int qsum(int x, int y)
{
    int ans = 0;
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        ans += query(id[top[x]], id[x], 1, n, 1);
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        swap(x, y);
    ans += query(id[son[x]], id[y], 1, n, 1);
    return ans;
}
void change(int x, int k)
{
    x--;
    update(id[e[2 * x].u], k, 1, n, 1); //因为是双向边,所以是e[2*x].u
}
int main()
{
    //freopen("in.txt", "r", stdin);
    int u, v, c;
    while (~scanf("%d%d", &n, &m))
    {
        init();
        for (int i = 1; i <= n - 1; i++)
        {
            scanf("%d%d%d", &u, &v, &c);
            add_edge(u, v, c);
            add_edge(v, u, c);
        }
        dfs1(1, 0, 1);
        dfs2(1, 1);
        for (int i = 0; i < tot; i += 2)
        {
            if (dep[e[i].u] < dep[e[i].v])
                swap(e[i].u, e[i].v);
            w[id[e[i].u]] = e[i].w; //易错点,是w[id[e[i].u]]
        }
        build(1, n, 1);
        while (m--)
        {
            int op, x, y;
            scanf("%d%d%d", &op, &x, &y);
            if (op == 0)
                change(x, y);
            else
                printf("%d\n", qsum(x, y));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/riba2534/article/details/81071509
今日推荐