图论之树链剖分模板

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define MEM(a,b) memset(a,b,sizeof(a));
int n,m,s;
const int maxn=100010;
struct Node{
    int u,v,w,next;
}e[maxn],edge[2*maxn];
int cnt;
int head[maxn];
//记siz[v]表示以v为根的子树的节点数,dep[v]表示v的深度(根深度为1),top[v]表示v所在的链的
//顶端节点,fa[v]表示v的父亲,son[v]表示与v在同一重链上的v的儿子节点(姑且称为重儿子),
//id[v]表示v与其父亲节点的连边(姑且称为v的父边)在线段树中的位置。
int dep[maxn],siz[maxn],son[maxn],fa[maxn];
int top[maxn],id[maxn];top 最近的重链父节点
int num;
void addedge(int u,int v){
    edge[cnt].u=u;edge[cnt].v=v;edge[cnt].next=head[u]++;head[u]=cnt++;
}
void dfs1(int u,int f,int d){
    dep[u]=d;
    siz[u]=1;
    son[u]=0;
    fa[u]=f;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==f)continue;
        dfs1(v,u,d+1);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v])
            son[u]=v;
    }
}
void dfs2(int u,int tp){
    top[u]=tp;
    id[u]=++num;
    if(son[u])dfs2(son[u],tp);
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==fa[u]||v==son[u])continue;
        dfs2(v,v);
    }
}
struct Tree{
    int l,r,val;
}tree[4*maxn];

#define lson 2*o,l,mid
#define rson 2*o+1,mid+1,r
int Val[maxn];

void pushup(int x){
    tree[x].val=tree[2*x].val+tree[2*x+1].val;
}
void build(int o,int l,int r){//建树一致
    tree[o].l=l;tree[o].r=r;
    if(l==r){
        tree[o].val=Val[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(o);
}
void update(int o,int a,int b){//更新操作一致
    if(tree[o].l==tree[o].r){
        tree[o].val=b;
        return;
    }
    int mid=(tree[o].l+tree[o].r)>>1;
    if(a<=mid)
        update(2*o,a,b);
    else
        update(2*o+1,a,b);
    pushup(o);
}
int query(int o,int l,int r){
    if(tree[o].l>=l&&tree[o].r<=r){
        return tree[o].val;
    }
    int mid=(tree[o].l+tree[o].r)>>1;
    if(r<=mid)
        return query(2*o,l,r);
    else if(l>mid)
        return query(2*o+1,l,r);
    else
        return query(lson)+query(rson);
}
int find(int u,int v){
    int tp1=top[u],tp2=top[v];
    int ans=0;
    while(tp1!=tp2){
        if(dep[tp1]<dep[tp2]){
            swap(tp1,tp2);
            swap(u,v);
        }
        ans+=query(1,id[tp1],id[u]);
        u=fa[tp1];
        tp1=top[u];
    }
    if(u==v)return ans;
    if(dep[u]>dep[v])swap(u,v);
    ans+=query(1,id[son[u]],id[v]);
    return ans;
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    cnt=0;num=0;
    MEM(head,-1);
    for(int i=1;i<n;i++){
        scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        addedge(e[i].u,e[i].v);
        addedge(e[i].v,e[i].u);
    }
    dfs1(1,0,1);
    dfs2(1,1);
    for(int i=1;i<n;i++){
        if(dep[e[i].u]<dep[e[i].v])
            std::swap(e[i].u,e[i].v);
        Val[id[e[i].u]]=e[i].w;
    }
    build(1,1,num);
    for(int i=0;i<m;i++){
        int ok,x,y;
        scanf("%d",&ok);
        if(ok==0){
            scanf("%d",&x);
            printf("%d\n",find(s,x));
            s=x;
        }
        else{
            scanf("%d%d",&x,&y);
            update(1,id[e[x].u],y);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值