zoukankan      html  css  js  c++  java
  • fzu 2082 过路费 (树链剖分+线段树 边权)

    Problem 2082 过路费

    Accept: 887    Submit: 2881
    Time Limit: 1000 mSec    Memory Limit : 32768 KB

     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
     
    思路:
    基于边权进行树链剖分
    题目说了半天其实就是给你一棵树,修改边权,询问两点之间边的权值和(n个点,n-1条边,点两两互通,摆明了是树结构了),
    基于边权的树链剖分和基于点权的处理方面上有些不同。
    观察一棵树的结构我们可以看出树上每一个点都可以一一对应和他的父节点相连的边,那么我们就可以用这些点表示树上的边进行
    树链剖分。代码算非常裸的树链剖分+线段树区间和,只要注意下一些处理上的小细节就好了。
     
    实现代码:
    #include<iostream>
    #include<cstring>
    using namespace std;
    #define ll long long
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define mid ll m = (l + r) >> 1;
    const ll M = 1e5+10;
    ll sum[M<<2],son[M],siz[M],head[M],top[M],fa[M],dep[M],tid[M<<2],rk[M<<2];
    ll u[M],v[M],cnt1,cnt,wt[M],n,m;
    struct node{
        ll to,next,w;
    }e[M];
    
    void add(ll u,ll v,ll c){
        e[++cnt1].to=v;e[cnt1].next=head[u];e[cnt1].w=c;head[u]=cnt1;
        e[++cnt1].to=u;e[cnt1].next=head[v];e[cnt1].w=c;head[v]=cnt1;
    }
    void dfs1(ll u,ll faz,ll deep){
        dep[u] = deep;
        siz[u] = 1;
        fa[u] = faz;
        for(ll i = head[u];i ;i=e[i].next){
            ll v = e[i].to;
            if(v != fa[u]){
                wt[v] = e[i].w;
                dfs1(v,u,deep+1);
                siz[u] += siz[v];
                if(son[u]==-1||siz[v]>siz[son[u]])
                    son[u] = v;
            }
        }
    }
    
    void dfs2(ll u,ll t){
        top[u] = t;
        tid[u] = cnt;
        rk[cnt] = wt[u];
        //cout<<1<<endl;
        cnt++;
        if(son[u] == -1) return ;
        dfs2(son[u],t);
        for(ll i = head[u];i;i=e[i].next){
            ll v = e[i].to;
            if(v != son[u]&&v != fa[u])
                dfs2(v,v);
        }
    }
    
    void pushup(ll rt){
        sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    }
    
    void update(ll p,ll c,ll l,ll r,ll rt){
        if(l == r){
            sum[rt] = c;
            return;
        }
        mid;
        if(p <= m) update(p,c,lson);
        else update(p,c,rson);
        pushup(rt);
    }
    
    void build(ll l,ll r,ll rt){
        if(l == r){
            sum[rt] = rk[l];
            return ;
        }
        mid;
        build(lson);
        build(rson);
        pushup(rt);
    }
    
    ll query(ll L,ll R,ll l,ll r,ll rt){
        if(L <= l&&R >= r){
            return sum[rt];
        }
        mid;
        ll ret = 0;
        if(L <= m) ret += query(L,R,lson);
        if(R > m) ret += query(L,R,rson);
        return ret;
    }
    
    ll ask(ll x,ll y){
        ll ans = 0;
        ll fx = top[x],fy = top[y];
        while(fx != fy){
            if(dep[fx] < dep[fy]) swap(fx,fy),swap(x,y);
            if(fx == 1) ans += query(tid[fx]+1,tid[x],1,n,1);
            else ans += query(tid[fx],tid[x],1,n,1);
            x = fa[fx]; fx = top[x];
        }
        //当x,y top相同时,因为当前这个点代表的是它与父节点之前的边的权值
        //top相同时有两种情况:1。两点重合,2.两点在同一重链上
        if(x==y) return ans;  //两点重合时直接返回当前的值就好了。
        if(dep[x] > dep[y]) swap(x,y);
        ans += query(tid[x]+1,tid[y],1,n,1); //当两点在同一重链上时,dep较小的边需要+1。
        return ans;
    }
    
    void init()
    {
        memset(son,-1,sizeof(son));
        for(ll i = 0; i <= n;i ++){
            e[i].to = 0;e[i].w = 0;e[i].next = 0;head[i] = 0;
        }
    }
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0); cout.tie(0);
        ll c,x,a,b;
        while(cin>>n>>m){
        init();
        cnt1 = 1;cnt = 1;
        for(ll i = 1;i < n;i ++){
            cin>>u[i]>>v[i]>>c;
            add(u[i],v[i],c);
        }
        dfs1(1,0,1);
        dfs2(1,1);
        //cout<<1<<endl;
        build(1,n,1);
        while(m--){
           cin>>x>>a>>b;
           if(x==0){
               if(dep[u[a]] < dep[v[a]]) swap(u[a],v[a]);
               update(tid[u[a]],b,1,n,1);
           }
           else{
            cout<<ask(a,b)<<endl;
           }
        }
        }
        return 0;
    }
  • 相关阅读:
    JavaScript实现类的private、protected、public、static以及继承
    OSS网页上传和断点续传(STSToken篇)
    OSS网页上传和断点续传(OSS配置篇)
    Linq sum()时遇到NULL
    SQLSERVER事务日志已满 the transaction log for database 'xx' is full
    笔记本高分辨软件兼容问题,字体太小或模糊
    H5上传图片之canvas
    An error occurred while updating the entries. See the inner exception for details.
    无限级结构SQL查询所有的下级和所有的上级
    SQLserver 进程被死锁问题解决
  • 原文地址:https://www.cnblogs.com/kls123/p/8922325.html
Copyright © 2011-2022 走看看