fzu Problem 2082 过路费 树链剖分 LCT 动态树

Problem 2082 过路费

Accept: 393    Submit: 1301
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月(校赛热身赛)


分析:

对每个点建立一个结点,值为0

对每个边建立一个结点,值为边权。

然后用LCT维护即可



#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
#define maxn 500007
#define inf  1000000000
#define ll int

struct Node{
    Node *fa,*ch[2];
    bool rev,root;
    int val;
    ll minv;
};
Node pool[maxn];
Node *nil,*tree[maxn];
int cnt = 0;
void init(){
    cnt = 1;
    nil = tree[0] = pool;
    nil->ch[0] = nil->ch[1] = nil;
    nil->val = 0;
    nil->minv = 0;
}
Node *newnode(int val,Node *f){
    pool[cnt].fa = f;
    pool[cnt].ch[0]=pool[cnt].ch[1]=nil;
    pool[cnt].rev = false;
    pool[cnt].root = true;
    pool[cnt].val = val;
    pool[cnt].minv = val;
    return &pool[cnt++];
}

//左右子树反转******真正把结点变为根
void update_rev(Node *x){
    if(x == nil) return ;
    x->rev = !x->rev;
    swap(x->ch[0],x->ch[1]);
}
//splay向上更新信息******
void update(Node *x){
    if(x == nil) return ;
    x->minv = x->val;
    Node*y = x->ch[0];
    if(y->minv > x->minv)
        x->minv = y->minv;
    y = x->ch[1];
    if(y->minv > x->minv)
        x->minv = y->minv;
}

//splay下推信息******
void pushdown(Node *x){
    if(x->rev != false){
        update_rev(x->ch[0]);
        update_rev(x->ch[1]);
        x->rev = false;
    }
}
//splay在root-->x的路径下推信息******
void push(Node *x){
    if(!x->root) push(x->fa);
    pushdown(x);
}
//将结点x旋转至splay中父亲的位置******
void rotate(Node *x){
    Node *f = x->fa, *ff = f->fa;
    int t = (f->ch[1] == x);
    if(f->root)
        x->root = true, f->root = false;
    else ff->ch[ff->ch[1] == f] = x;
    x->fa = ff;
    f->ch[t] = x->ch[t^1];
    x->ch[t^1]->fa = f;
    x->ch[t^1] = f;
    f->fa = x;
    update(f);
}
//将结点x旋转至x所在splay的根位置******
void splay(Node *x){
    push(x);
    Node *f, *ff;
    while(!x->root){
        f = x->fa,ff = f->fa;
        if(!f->root)
            if((ff->ch[1]==f)&&(f->ch[1] == x)) rotate(f);
            else rotate(x);
        rotate(x);
    }
    update(x);
}
//将x到树根的路径并成一条path******
Node *access(Node *x){
    Node *y = nil,*z;
    while(x != nil){
        splay(x);
        x->ch[1]->root = true;
        (x->ch[1] = y)->root = false;
        update(x);
        y = x;
        x = x->fa;
    }
    return y;
}
//将结点x变成树根******
void be_root(Node *x){
    access(x);
    splay(x);
    update_rev(x);
}
//将x连接到结点f上******
void link(Node *x, Node *f){
    be_root(x);
    x->fa = f;
}
Node * find(Node *root){
    if(root->ch[0] == nil) return root;
    return find(root->ch[0]);
}
Node*road[maxn];
int main(){
    int n,q,t;
    Node*x,*y,*z;
    scanf("%d",&t);
    char word[20];
    while(t--){
        scanf("%d",&n);

        init();
        int u,v,t;
        for(int i = 1;i <= n; i++)
            tree[i] = newnode(0,nil);
        for(int i = 1;i < n ;i++){
            scanf("%d%d%d",&u,&v,&t);
            road[i] = x = newnode(t,nil);
            link(tree[u],x);
            link(tree[v],x);
        }
        while(1){
            scanf("%s",word);
            if(word[0] == 'D') break;
            scanf("%d%d",&u,&v);
            if(word[0] == 'Q'){
                be_root(tree[u]);
                y = access(tree[v]);
                printf("%d\n",y->minv);
            }
            else {
                splay(road[u]);
                road[u]->val = v;
                update(road[u]);
            }
        }
    }

    return 0;
}

/*
3 100 1
1 2 1
2 3 2
0 2
1 2 3
0 3
1 2 5
0 2

*/



你可能感兴趣的:(problem,动态树,树链剖分,过路费,FZU,LCT,2082)