1 条题解

  • 0
    @ 2025-1-13 16:49:44

    考虑拆贡献。

    我们考虑用一个点来表示一条边,假设一条边连接 (u,v)(u,v)uuvv 的父节点,那么我们可以用点 uu 来代表这条边,容易证明每条边都存在唯一的点来代表它。

    所以我们考虑计算有多少条简单路径经过这条边即可,显然对于 uu 对应的边来说,有 sizu(nsizu)siz_u\cdot(n-siz_u) 条简单路径经过它,那么我们就需要把答案更新为 ansans+wsizu(nsizu)ans\gets ans+w\cdot siz_u\cdot(n-siz_u)

    现在考虑修改操作,显然只需要维护一下增量即可,那增量可以写成:

    $$\Delta=z\cdot \sum_{x\in u\to v 的路径上}siz_x\cdot(n-siz_x) $$

    只需要求出后面一坨 \sum 里的数即可,显然树上前缀和可做,时间复杂度 O(mlogn)O(m\log n)

    不要忘记把答案更新为 ansans+Δans\gets ans+\Delta

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #define ll long long
    using namespace std;
    const ll N=1e5+10;
    const ll MOD=1e9+7;
    ll n,fa[N][30],siz[N],dat[N],sum[N],dep[N];
    ll ans;
    vector<ll> e[N],quan[N];
    void dfs(ll u,ll f,ll d){
    	siz[u]=1;
    	ll lz=e[u].size();
    	for(ll i=0;i<lz;i++){
    		ll v=e[u][i];
    		if(v==f) continue;
    		dfs(v,u,quan[u][i]);
    		siz[u]+=siz[v];
    	}
    	dat[u]=siz[u]*(n-siz[u])%MOD;
    	ans=(ans+dat[u]*d%MOD+MOD)%MOD;
    }
    void dfs2(ll u,ll f){
    	dep[u]=dep[f]+1;
    	fa[u][0]=f;
    	for(ll i=1;i<30;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
    	sum[u]=(sum[f]+dat[u])%MOD;
    	ll lz=e[u].size();
    	for(ll i=0;i<lz;i++){
    		ll v=e[u][i];
    		if(v==f) continue;
    		dfs2(v,u); 
    	}
    }
    ll lca(ll x,ll y){
    	if(dep[x]<dep[y]) swap(x,y);
    	for(ll i=29;i>=0;i--){
    		if(dep[fa[x][i]]>=dep[y]){
    			x=fa[x][i];
    		} 
    	}
    	if(x==y) return x;
    	for(ll i=29;i>=0;i--){
    		if(fa[x][i]!=fa[y][i]){
    			x=fa[x][i];
    			y=fa[y][i];
    		}
    	}
    	return fa[x][0];
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin.tie(0),cout.tie(0);
    	cin>>n;
    	for(ll i=1;i<n;i++){
    		ll u,v,w;
    		cin>>u>>v>>w;
    		e[u].push_back(v);
    		e[v].push_back(u);
    		quan[u].push_back(w);
    		quan[v].push_back(w);
    	}
    	dfs(1,0,0);
    	dfs2(1,0);
    	cout<<ans<<"\n";
    	ll q;
    	cin>>q;
    	while(q--){
    		ll L,R,z,minu;
    		cin>>L>>R>>z;
    		minu=sum[L]+sum[R]-2*sum[lca(L,R)];
    		minu%=MOD;
    		if(minu<0) minu+=MOD;
    		ans=(ans+minu*z%MOD+MOD)%MOD;
    		cout<<ans<<"\n";
    	}
    	return 0;
    } 
    
    • 1

    信息

    ID
    12
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    (无)
    递交数
    2
    已通过
    2
    上传者