FZU 2082 过路费 (树链剖分)边权

来源:互联网 发布:漫画集软件 编辑:程序博客网 时间:2024/05/01 04:39
Problem 2082 过路费

Accept: 322    Submit: 1101
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 31 2 11 1 20 1 21 2 1

Sample Output

12

Source

FOJ有奖月赛-2012年4月(校赛热身赛)

解题:一道 裸树的树链剖分

#include<stdio.h>#include<string.h>#define LL __int64const int N = 50005;int head[N<<1],to[N<<1],next1[N<<1],tot;int deep[N],fath[N],son[N],num[N];int top[N],p[N],pos;void init(){    pos=tot=0;    memset(head,-1,sizeof(head));}void addEdge(const int& u, const int& v){    to[tot] = v, next1[tot] = head[u], head[u] = tot++;}void addUndirEdge(const int& u, const int& v){    addEdge(u, v), addEdge(v, u);}void dfs1(int u,int pre,int d){     fath[u]=pre;     deep[u]=d;     son[u]=-1;     num[u]=1;     for(int i=head[u]; i!=-1; i=next1[i]){         int v=to[i];         if(v==fath[u])continue;         dfs1(v,u,d+1);         num[u]+=num[v];         if(son[u]==-1||num[v]>num[son[u]])            son[u]=v;     }}void getpos(int u,int root){    top[u]=root;    p[u]=pos++;    if(son[u]==-1)        return ;    getpos(son[u],root);    for(int i=head[u]; i!=-1; i=next1[i]){        int v=to[i];        if(v==son[u]||v==fath[u])            continue;        getpos(v,v);    }}LL root[N*3],cost[N];void pushUp(int k){    root[k]=root[k<<1]+root[k<<1|1];}void build(int l, int r, int k){    if(l==r){        root[k]=cost[l]; return ;    }    int mid=(l+r)>>1;    build(l,mid,k<<1);    build(mid+1,r,k<<1|1);    pushUp(k);}void update(int l, int r, int k, const int& id, LL c){    if(l==r){        root[k]=c; return ;    }    int mid=(l+r)>>1;    if(id<=mid)        update(l,mid,k<<1,id,c);    else        update(mid+1,r,k<<1|1,id,c);    pushUp(k);}LL query(int l, int r, int k, const int& L, const int& R){    if(L<=l&&r<=R){        return root[k];    }    int mid=(l+r)>>1;    LL sum=0;    if(L<=mid)        sum+=query(l,mid,k<<1,L,R);    if(mid<R)        sum+=query(mid+1,r,k<<1|1,L,R);    return sum;}void swp(int &u,int &v){    int tt=u; u=v; v=tt;}LL solve(int u,int v){    int fu=top[u], fv=top[v];    LL sum=0;    while(fu!=fv){        if(deep[fu]<deep[fv]){            swp(fu,fv); swp(u,v);        }        sum+=query(1,pos,1,p[fu],p[u]);        u=fath[fu]; fu=top[u];    }    if(u==v)return sum;    if(deep[u]>deep[v])        swp(u,v);    sum+=query(1,pos,1,p[son[u]],p[v]);//一不小心p[son[u]]写成了p[u]让我WA了好几次(求边权用p[son[u]],求点权用p[u])    return sum;}struct EDG{    int u,v;    LL c;}edg[N];int main(){    int n,m,op,a,b;    while(scanf("%d%d",&n,&m)>0){        init();        for(int i=1; i<n; i++){            scanf("%d%d%I64d",&edg[i].u,&edg[i].v,&edg[i].c);            addUndirEdge(edg[i].u, edg[i].v);        }        dfs1(1,1,1);        getpos(1,1);        for(int i=1; i<n; i++){            if(deep[edg[i].u]>deep[edg[i].v])                swp(edg[i].u, edg[i].v);            cost[p[edg[i].v]]=edg[i].c;        }        pos=n;        build(1,pos,1);        while(m--){            scanf("%d%d%d",&op,&a,&b);            if(op==0)                update(1,pos,1,p[edg[a].v],b);            else                printf("%I64d\n",solve(a,b));        }    }}


0 0
原创粉丝点击