树链剖分+BIT - FZU 2082 - 过路费

树链剖分+BIT - FZU 2082 - 过路费

核心思路:

  1. 边权转化为点权:树上某一条边可以唯一转化为子节点的点权
  2. BIT维护单点修改+区间查询

注意本题有多组输入,每组样例需要重新init

#include <cstdio>
#include <vector>
#include <cstdlib>

using namespace std;

const int N = 5e4+5;

int n, m;
int a;
int b, c;


struct Node{
    int v;
    int d;
    Node(){};
    Node(int _v,int _d){
        v = _v;
        d = _d;
    }
};

vector<Node> edges[N];

vector<Node> vec(1);

int head[N];
int fa[N];
int dep[N];
int heavy_son[N];
int dfs_id[N];
int dfs_begin[N];
int dfs_end[N];

int w[N];   // 节点i到其父节点的边的边权

int tree[N];

int dfs1(int cur, int prev, int depth){
    fa[cur] = prev;
    dep[cur] = depth;
    int tot_size = 1, cur_size = 0,max_size = 0, max_root = 0;

    for(vector<Node>::iterator it = edges[cur].begin(); it != edges[cur].end(); ++it){
        if(it->v == prev) continue;
        w[it->v] = it->d;  // 节点i到其父节点的边的边权
        cur_size = dfs1(it->v, cur, depth+1);
        tot_size += cur_size;
        if(cur_size > max_size){
            max_size = cur_size;
            max_root = it->v;
        }
    }
    heavy_son[cur] = max_root;
    return tot_size;
}

void dfs2(int cur, int prev, int head_node, int& id){
    head[cur] = head_node;
    dfs_id[cur] = id++;

    if(heavy_son[cur]){
        dfs2(heavy_son[cur], cur, head_node, id);
    }
    for(vector<Node>::iterator it = edges[cur].begin(); it != edges[cur].end(); ++it){
        if(it->v == prev || it->v == heavy_son[cur]) continue;
        dfs2(it->v, cur, it->v, id);   
    }
    dfs_begin[cur] = dfs_id[cur];
    dfs_end[cur] = id-1;
}


void build_lct(){
    int id = 1;
    dfs1(1, 0, 1);
    dfs2(1, 0, 1, id);
}

int low_bit(int x){
    return -x & x;
}

int query(int pos){
    int ans = 0;
    while(pos >= 1){
        ans += tree[pos];
        pos -= low_bit(pos);
    }
    return ans;
}

void modify(int pos, int v){
    int delta = v - query(pos) + query(pos-1);
    while(pos <= n){
        tree[pos] += delta;
        pos += low_bit(pos);
    }
}



int query_lct(int a, int b){
    int ha, hb;
    int ans = 0;
    while(1){
        ha = head[a];
        hb = head[b];
        if(ha == hb){
            a = dfs_id[a];
            b = dfs_id[b];
            if(a > b) swap(a, b);
            ans += query(b) - query(a);
            break;
        }else{
            if(dep[ha] < dep[hb]){
                swap(a, b);
                swap(ha, hb);
            }
            ans += query(dfs_id[a]) - query(dfs_id[ha]-1);
            a = fa[ha];
        }
    }
    return ans;
}

void init(int n){
    for(int i = 1; i <= n; ++i){
        edges[i].clear();
    }
    vec.clear();
    vec.push_back(Node());

    int head[N];
    for(int i = 1; i <= n; ++i){
        heavy_son[i] = 0;
    }
    for(int i = 0; i < n; ++i){
        tree[i] = 0;
    }
}
int main(){
    while(scanf("%d%d", &n, &m)!=EOF){
        init(n);
        for(int i = 1; i < n; ++i){
            scanf("%d%d%d", &a, &b, &c);
            edges[a].push_back(Node(b, c));
            edges[b].push_back(Node(a, c));
            vec.push_back(Node(a, b));
        }

        build_lct();
        for(int i = 1; i <= n; ++i){
            modify(dfs_id[i], w[i]);
        }

        for(int i = 1; i < n; ++i){
            if(fa[vec[i].v] != vec[i].d) swap(vec[i].v, vec[i].d);
        }

        while(m--){
            scanf("%d%d%d", &a, &b, &c);
            if(a == 0){
                modify(dfs_id[vec[b].v], c);
            }else{
                printf("%d\n",query_lct(b, c));
            }
        }
    }

    // system("pause");
    return 0;
}

/*
附自制测试用例
6 2
1 2 2
1 3 1
2 4 3
3 5 7
3 6 5
1 4 6
1 4 6
6 2
1 2 2
1 3 1
2 4 3
3 5 7
3 6 5
1 4 6
1 4 6
*/
posted @ 2021-03-02 21:33  popozyl  阅读(44)  评论(0编辑  收藏  举报