CF593D. Happy Tree Party(树剖模板)

https://codeforces.com/problemset/problem/593/D

看到题目是逐步向下取整我还想了一下……其实对于整型来说和把路径上的值乘在一起统一除效果是一样的。

这题还有一个点就是它的权值是依附于边而非点,对此我们可以把每个点和它连向fa的边绑定,把这个权值重新转换到点上,因为每个点只有一个fa。而对于根我们可以给它一个向上的虚边赋值1,这个过程用一个简单dfs来做

实际写题当中wa了好久……最后才发现是线段树的update参数没用ll

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e5+2;
const ll inf=1e18;
#define lson (o<<1)
#define rson (o<<1|1)
int n,m;
struct edge{
    int to,next;
    ll x;
}es[maxn<<1];
int cnt,head[maxn];
void add(int u,int v,ll x){
    es[++cnt]={v,head[u],x};
    head[u]=cnt;
}

ll mul(ll a,ll b){
    if(inf/a<b)
        return inf+5;
    return a*b;
}

int fa[maxn],dep[maxn],son[maxn],siz[maxn];
void dfs1(int o,int from,int d){
    fa[o]=from;
    dep[o]=d;
    siz[o]=1;
    int tmp=0;
    for(int i=head[o];i;i=es[i].next){
        int v=es[i].to;
        if(v==from)
            continue;
        dfs1(v,o,d+1);
        if(siz[v]>tmp){
            tmp=siz[v];
            son[o]=v;
        }
        siz[o]+=siz[v];
    }
}

int dfn[maxn],top[maxn],rnk[maxn],tot;
void dfs2(int o,int t){
    dfn[o]=++tot;
    rnk[dfn[o]]=o;
    top[o]=t;
    if(son[o]){
        dfs2(son[o],t);
    }
    for(int i=head[o];i;i=es[i].next){
        int v=es[i].to;
        if(dfn[v]||v==son[o])
            continue;
        dfs2(v,v);
    }
}

ll val[maxn<<2];
ll xp[maxn];
void build(int o,int l,int r){
    //节点o管辖[l,r]区间
    //val[o]=1;
    if(l==r){
        val[o]=xp[rnk[l]];
        return ;
    }
    int mid=(l+r)/2;
    build(lson,l,mid);
    build(rson,mid+1,r);
    //val[o]=(val[lson]>inf/val[rson]?inf+5:val[lson]*val[rson]);
    val[o]=mul(val[lson],val[rson]);
}

void update(int o,int l,int r,int pos,ll c){
    //将pos位置的xp替换为c
    if(l==r){
        val[o]=c;
        return ;
    }
    int mid=(l+r)/2;
    if(pos<=mid){
        update(lson,l,mid,pos,c);
    }else{
        update(rson,mid+1,r,pos,c);
    }
    //val[o]=(val[lson]>inf/val[rson]?inf+5:val[lson]*val[rson]);
    val[o]=mul(val[lson],val[rson]);
}

ll query(int o,int l,int r,int L,int R){
    if(l>=L&&r<=R){
        return val[o];
    }
    int mid=(l+r)/2;
    ll res=1;
    if(L<=mid){
        res=mul(res,query(lson,l,mid,L,R));
    }
    if(R>mid){
        ll tmp=query(rson,mid+1,r,L,R);
        //res=(res>1e18/tmp?inf+5:res*tmp);
        res=mul(res,tmp);
    }
    return res;
}

void dfs3(int o){
    //用来把边权转化为儿子的点权
    for(int i=head[o];i;i=es[i].next){
        int v=es[i].to;
        if(fa[v]==o){
            xp[v]=es[i].x;
            dfs3(v);
        }
    }
}

ll solve(int a,int b){
    ll res=1,tmp;
    int ta=top[a],tb=top[b];
    while(ta!=tb){
        if(dep[ta]<dep[tb]){
            swap(ta,tb);
            swap(a,b);
        }

        tmp=query(1,1,n,dfn[ta],dfn[a]);
        //res=(res>1e18/tmp?inf+5:res*tmp);
        res=mul(res,tmp);
        a=fa[ta];
        ta=top[a];
    }
    if(a!=b){
        if(dep[a]<dep[b])
            swap(a,b);
        tmp=query(1,1,n,dfn[son[b]],dfn[a]);
        //res=(res>1e18/tmp?inf+5:res*tmp);
        res=mul(res,tmp);
    }
    return res;
}

int main(){
    cin>>n>>m;
    for(int i=1,u,v;i<n;i++){
        ll x;
        cin>>u>>v>>x;
        add(u,v,x);
        add(v,u,x);
    }
    dfs1(1,0,1);
    dfs2(1,1);
    dfs3(1);
    xp[rnk[1]]=1;
    build(1,1,n);
    for(int i=1,opt;i<=m;i++){
        cin>>opt;
        if(opt==1){
            int a,b;
            ll y,x;
            cin>>a>>b>>y;
            x=solve(a,b);
            cout<<y/x<<endl;
        }else{
            int pos;
            ll c;
            cin>>pos>>c;
            int u=es[pos*2-1].to,v=es[pos*2].to;
            if(fa[v]!=u)
                swap(u,v);
            update(1,1,n,dfn[v],c);
        }
    }
}

/*
4 3
1 2 1
2 4 3
2 3 2
2 3 4
1 3 4 6

*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Absoler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值