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

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 __int64
const 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));
        }
    }

}
时间: 2024-12-07 19:59:38

FZU 2082 过路费 (树链剖分)边权的相关文章

FZU 2082 过路费(树链剖分)

FZU 2082 过路费 题目链接 树链抛分改动边的模板题 代码: #include <cstdio> #include <cstring> #include <vector> using namespace std; typedef long long ll; const int N = 50005; int dep[N], id[N], sz[N], top[N], son[N], fa[N], idx; int n, m; ll bit[N]; struct Ed

FZU 2082 过路费 (树链剖分)

树链剖分裸题...不多说.. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <stdio.h> using namespace

FZU 2082 过路费(树链抛分)

FZU 2082 过路费 题目链接 树链抛分修改边的模板题 代码: #include <cstdio> #include <cstring> #include <vector> using namespace std; typedef long long ll; const int N = 50005; int dep[N], id[N], sz[N], top[N], son[N], fa[N], idx; int n, m; ll bit[N]; struct Ed

FZU Problem 2082 过路费 树链剖分

Problem 2082 过路费  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 &

Problem 2082 过路费树链剖分

裸题直接搞. #include<iostream> #include<cstdio> #include<cstring> #include<map> #include<vector> #include<stdlib.h> using namespace std; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 typedef long long LL;

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时... 代码如下: 1 //树链剖分 点权修改 修改单节点 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 using namespa

HDU3966 Aragorn&#39;s Story(树链剖分 点权 模版题)

#include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <map> #include <set> #include <vector> #include <cstdio> using namespace std; const int N=50010; s

hdu 5242 树链剖分找权值最大的前k条链

http://acm.hdu.edu.cn/showproblem.php?pid=5242 Problem Description It is well known that Keima Katsuragi is The Capturing God because of his exceptional skills and experience in ''capturing'' virtual girls in gal games. He is able to play k games sim

树链剖分——边上权值和

Queries On Tree Problem code: TAQTREE Tweet All submissions for this problem are available. Read problems statements in Mandarin Chinese and Russian. You are given a tree of N nodes numbered from 1 to N. The ith edge connecting node ui and vi has a w

【树链剖分】权值取反,区间最大

[题面] 有一棵n个点的树,边按照1~n-1标号,每条边拥有一个边权 现在有 m 次操作,每次操作为如下三种之一: . 1 x y:边x的权值改为y . 2 x y:将点x到点y路径上的所有边权值变成相反数 . 3 x y:查询点x到点y路径上的最大边权 第一行为两个整数n,m,表示序列长度和操作次数 接下来n-1行,每行三个数a,b,v,表示a,b之间有一条权值为v的边,按照标号1~n-1的顺序给出 接下来m行, 每行以1/2/3作为第一个数,表示操作种类.接下来两个整数,格式如题,表示一次操