poj2763 LCT

题意:给出树的边权 要求的操作是修改某条边的边权 然后询问是两个点之间的距离 

解法:边权转点权啊 然后就去掉lca 这个操作真的太神 然后真的太轻松了 据说线段树也能写这题 大概是转成dfs序 

边权怎么维护还没有想到

#include<queue>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<stdlib.h>
#include<algorithm>
using namespace std;
#define MAXN 111111
#define ls ch[rt][0]
#define rs ch[rt][1]
int ch[MAXN][2],fa[MAXN],sum[MAXN],val[MAXN],_rt[MAXN];
inline void up(int rt){sum[rt]=val[rt]+sum[ls]+sum[rs];}
inline void rot(int rt){
    int f=fa[rt],side=ch[f][1]==rt,ll=ch[rt][!side];
    fa[ll]=f,ch[f][side]=ll;
    fa[rt]=fa[f];
    if(_rt[f])_rt[rt]=1,_rt[f]=0;
    else ch[fa[f]][ch[fa[f]][1]==f]=rt;
    fa[f]=rt,ch[rt][!side]=f;
    up(f),up(rt);
}
inline void splay(int rt){
    while(!_rt[rt]){
        int f=fa[rt],ff=fa[f];
        if(_rt[f])rot(rt);
        else if((ch[ff][1]==f)==(ch[f][1]==rt))rot(f),rot(rt);
        else rot(rt),rot(rt);
    }
}
inline int ace(int rt){
    int y=0;
    for(;rt;y=rt,rt=fa[rt]){
        splay(rt);
        _rt[rs]=1,rs=y;_rt[rs]=0;
        up(rt);
    }return y;
}
inline void lca(int &u,int &v){
    ace(v),v=0;
    while(u){
        splay(u);
        if(!fa[u])return ;
        _rt[ch[u][1]]=1;ch[u][1]=v;_rt[v]=0;
        up(u);v=u;
        u=fa[u];
    }
}
inline void change(int u,int k){
    ace(u);val[u]=k;up(u);
}
inline void query(int u,int v){
    lca(u,v);
    printf("%d\n",sum[v]+sum[ch[u][1]]);
}
struct edge{
    int v,next,val,idx;
}e[MAXN<<1];
int head[MAXN],tot,id[MAXN];
inline void add(int u,int v,int val,int index){
    e[tot].v=v;e[tot].next=head[u];
    e[tot].val=val;e[tot].idx=index;
    head[u]=tot++;
}
inline void dfs(int u){
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(fa[v]!=0)continue;
        fa[v]=u;
        id[e[i].idx]=v;val[v]=e[i].val;
        dfs(v);
    }
}
inline void init(){tot=0;memset(head,-1,sizeof head);}
int u,v,w,n,m,op,a,b;
int main(){
    while(~scanf("%d%d%d",&n,&m,&u)){
        init();

        for(int rt=0;rt<=n;++rt){
            fa[rt]=ls=rs=0;_rt[rt]=1;
        }
        val[0]=sum[0]=0;
        for(int i=1;i<n;++i){
            scanf("%d%d%d",&a,&b,&w);
            add(b,a,w,i);add(a,b,w,i);
        }fa[1]=-1;dfs(1);fa[1]=0;
//        for(int i=1;i<=n;++i)printf("%d ",val[i]);
        while(m--){
            scanf("%d",&op);
            if(op==1){scanf("%d%d",&a,&v);change(id[a],v);}
            else{
                scanf("%d",&v);
//                printf("%d %d\n",u,v);
                query(u,v);
                u=v;
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值