树链剖分(SPOJ 375)

这是一道经典的树链剖分的题目。
它涉及了边的最大值查询。
题意:
给你n个点,有n-1条边,2个操作。
1.“QUERY”查询x,y之间边的最大值
2.“CHANGE”,将第x条边的权值该为y
3.以“DONE”结束

这将一个点来对应一条边。
这个巧妙之处自行体会。
这与点之间还是有差异;

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define For(aa,bb,cc) for(int aa=bb;aa<=cc;++aa)
#define Set(aa,bb) memset(aa,bb,sizeof(aa))
#define begin Begin
#define to To
#define next Next
#define rank Rank
#define lr node<<1
#define rr node<<1|1
using namespace std;
const int maxn=10010<<2;
int n,sum;
int begin[maxn],to[maxn],w[maxn],next[maxn],e;
int tree[maxn],rank[maxn],top[maxn],dep[maxn],tid[maxn],son[maxn],size[maxn],fa[maxn],num[maxn];
struct md{
    int m,d,z;
}a[maxn];

void add(int x,int y,int z){
    to[++e]=y,next[e]=begin[x],begin[x]=e,w[e]=z;
}

void dfs1(int node,int father,int deep){
    dep[node]=deep;
    fa[node]=father;
    size[node]=1;
    for(int i=begin[node];i;i=next[i]){
        int u=to[i];
        if(u!=father){
            dfs1(u,node,deep+1);
            size[node]+=size[u];
            if(son[node]==-1 || size[u]>size[son[node]]) son[node]=u;
        }
    }
    return ;
}

void dfs2(int node,int high){
    top[node]=high;
    tid[node]=++sum;
    rank[tid[node]]=node;
    if(son[node]==-1) return ;
    dfs2(son[node],high);
    for(int i=begin[node];i;i=next[i]){
        int u=to[i];
        if(u!=fa[node] && u!=son[node]){
            dfs2(u,u);
        }
    }
    return ;
}

void push_up(int node){
    tree[node]=max(tree[lr],tree[rr]);
}

void create_tree(int node,int l,int r){
    if(l==r){
        tree[node]=num[l];
    //cout<<node<<": "<<l<<' '<<r<<' '<<tree[node]<<endl;
        return ;
    }
    int mid=(l+r)>>1;
    create_tree(lr,l,mid);
    create_tree(rr,mid+1,r);
    push_up(node);
    //cout<<node<<": "<<l<<' '<<r<<' '<<tree[node]<<endl;
    return ;
}

int query(int node,int l,int r,int be,int en){
    if(be<=l && en>=r){
        return tree[node];
    }
    int mid=(l+r)>>1;
    if(en<=mid)return query(lr,l,mid,be,en);
    if(be>mid) return query(rr,mid+1,r,be,en);
    return max(query(lr,l,mid,be,mid),query(rr,mid+1,r,mid+1,en));
}

int ask(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans=max(ans,query(1,1,n,tid[top[x]],tid[x]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    if(x!=y)ans=max(ans,query(1,1,n,tid[x]+1,tid[y]));
    return ans;
}

void update(int node,int l,int r,int be,int ad){
    if(l==r){
        tree[node]=ad;
        return ;
    }
    int mid=(l+r)>>1;
    if(be<=mid) update(lr,l,mid,be,ad);
    if(be>mid) update(rr,mid+1,r,be,ad);
    push_up(node);
    return ;
}

void change(int x,int y){
    if(dep[a[x].m]>dep[a[x].d]){
        update(1,1,n,tid[a[x].m],y);
    }else{
        update(1,1,n,tid[a[x].d],y);
    }
    return ;
}

void work(){
    e=0,sum=0;
    Set(begin,0),Set(son,-1);
    scanf("%d",&n);
    For(i,1,n-1){
        scanf("%d%d%d",&a[i].m,&a[i].d,&a[i].z);
        add(a[i].m,a[i].d,a[i].z);
        add(a[i].d,a[i].m,a[i].z);
    }
    dfs1(1,0,0);
    dfs2(1,1);
    For(i,1,n-1){
        if(dep[a[i].m]>dep[a[i].d]){
            num[tid[a[i].m]]=a[i].z;
        }else{
            num[tid[a[i].d]]=a[i].z;
        }
    }
    create_tree(1,1,n);
    while(1){
        char s[20];int x,y;
        scanf("%s",s);
        if(s[0]=='D') return;
        scanf("%d%d",&x,&y);
        if(s[0]=='Q'){
            printf("%d\n",ask(x,y));
        }else{
            change(x,y);
        }
    }
}

int main(){
    int _;
    scanf("%d",&_);
    while(_--) work();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值