zoj 2082 过路费

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=55555;
int R[maxn],E[maxn];
int l[maxn],r[maxn];
int id[maxn];
int head[maxn];
int now,pos;
long long dp[maxn];
long long sum[maxn];
int d[maxn<<1][20];
bool vis[maxn];
struct edge{
    int u,v,p;
    long long w;
    edge(){}
    edge(int u,int v,int p,long long w):u(u),v(v),p(p),w(w){}
}e[maxn<<1];
int n,m,ecnt;
long long getsum(int x){
    long long res=dp[x];
    while(x)res+=sum[x],x-=x&-x;
    return res;
}
void update(int x,long long val){
    while(x<=n+1)sum[x]+=val,x+=x&-x;
}
void init_RMQ(){
    for(int i=0;i<pos;i++)d[i][0]=E[i];
    for(int j=1;(1<<j)<pos;j++)
    for(int i=0;i+(1<<j)-1<pos;i++)
    d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
int rmq(int l,int r){
    int k=0;
    while((1<<(k+1))<=r-l+1)k++;
    return min(d[l][k],d[r-(1<<k)+1][k]);
}
void dfs(int u,long long len){
    vis[u]=1;
    id[u]=now++;
    l[id[u]]=id[u];
    R[id[u]]=pos;
    E[pos++]=id[u];
    dp[id[u]]=len;
    for(int i=head[u];i!=-1;i=e[i].p){
        int v=e[i].v;
        if(vis[v])continue;
        dfs(v,len+e[i].w);
        E[pos++]=id[u];
    }
    r[id[u]]=now;
}
void run(){
    memset(head,-1,sizeof head);
    ecnt=0;
    int a,b;
    long long c;
    for(int i=0;i<n-1;i++){
        scanf("%d%d%I64d",&a,&b,&c);
        e[ecnt]=edge(a,b,head[a],c);
        head[a]=ecnt++;
        e[ecnt]=edge(b,a,head[b],c);
        head[b]=ecnt++;
    }
    pos=0,now=1;
    memset(vis,0,sizeof vis);
    dfs(1,0);
    init_RMQ();
    memset(sum,0,sizeof sum);
    while(m--){
        int op;
        scanf("%d",&op);
        if(op==1){
            scanf("%d%d",&a,&b);
            a=id[a];b=id[b];
            int lca=rmq(min(R[a],R[b]),max(R[a],R[b]));
            long long ans=getsum(a)+getsum(b)-2*getsum(lca);
            printf("%I64d\n",ans);
        }
        else {
            long long val;
            scanf("%d%I64d",&a,&val);
            int c=a*2-1;
            a=id[e[c].u],b=id[e[c].v];
            if(getsum(a)>getsum(b)){
                update(l[a],val-e[c].w);
                update(r[a],e[c].w-val);
            }
            else {
                update(l[b],val-e[c].w);
                update(r[b],e[c].w-val);
            }
            e[c].w=e[c-1].w=val;
        }
    }
}
int main()
{
//    freopen("in","r",stdin);
    while(scanf("%d%d",&n,&m)>0)run();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值