博客园 首页 私信博主 显示目录 隐藏目录 管理

蒜头君的树

蒜头君的树

2017-09-07


题目描述

蒜头君有一棵有根树,树的每一边都有边权,蒜头君想知道任意两点间最短距离之和为多少。另外,由于各种原因,蒜头君的树的边的边权会发生若干次改变,蒜头君想让你告诉他,每一次改变后,任意两点间最短距离之和为多少?


输入格式

第一行一个正整数 nn,表示蒜头君的树上的结点个数。

接下来 n-1n1 行,每行两个正整数 x_i,y_ixi​​,yi​​,x_ixi​​表示 i+1i+1 号结点的父亲结点的编号,保证其父结点编号小于自己编号。y_iyi​​ 表示 i+1i+1 号结点的父亲结点与自己间边的距离。

接下来一行一个整数 mm,表示树的边权发生改变的次数。

接下来 mm 行,每行两个正整数 a,ba,b,表示将 aa结点与其父亲结点之间的距离改为 bb,保证 a \ge 2a2。


输出格式

先输出一个整数,表示对于原始的树任意两点间最短距离之和。

接下来 mm 行,每行输出一个整数,表示每一次改变后,任意两点间最短距离之和。


数据规模


样例输入

4
1 1
1 1
1 1
1
2 2

样例输出

9
12

一道裸的dfs的题,不要看到树就害怕,当时模拟这个题的时候我看到树,一想就不会,现在看来,一条边的贡献就是左边点数*右边点数*w
只要单dfs一边找到一条边的孩子有多少就可以知道右边有多少....水题
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll long long 
const ll maxn=100000+9999;
using namespace std;
ll read(){
    ll an=0,f=1;char ch=getchar();
    while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-f;ch=getchar();}
    while('0'<=ch&&ch<='9'){an=an*10+ch-'0';ch=getchar();}
    return an*f;
}
ll f[maxn],w[maxn<<1],cnt,vis[maxn],size[maxn],n,m;
ll ans;
struct saber{
ll nex,to;
}b[maxn<<1];
void add(ll x,ll y,ll wi){
    cnt++;
    b[cnt].nex=f[x];
    b[cnt].to=y;
    w[cnt]=wi;
    f[x]=cnt;
}
void dfs(ll x){
    vis[x]=1;size[x]=1;
    for(ll i=f[x];i;i=b[i].nex){
        ll v=b[i].to;
        if(!vis[v]){
            vis[v]=1;
            dfs(v);
            size[x]+=size[v];
        }
    }
}
int main(){
    n=read();
    for(ll i=2;i<=n;i++){
        ll x,y;x=read();y=read();
        add(x,i,y);
    }
    dfs(1);
    m=read();
    for(ll i=1;i<n;i++){
        ans+=w[i]*(n-size[b[i].to])*(size[b[i].to]);
    }
    cout<<ans<<endl;
    while(m){m--;
    ll x,y,z;x=read();y=read();
        z=w[x-1];    w[x-1]=y;
        y=y-z;
        ans+=y*(n-size[b[x-1].to])*size[b[x-1].to];
        cout<<ans<<endl;
    }
    return 0;
}
s_a_b_e_r

注意数据会炸int,全部用ll。。。

posted @ 2017-09-07 15:02  ck666  阅读(241)  评论(0编辑  收藏  举报