EOJ Monthly 2018.8 D. Delivery Service (樹上差分)

https://acm.ecnu.edu.cn/contest/103/problem/D/

 

題意:

給你n個點n-1條邊和權值,q個起點和終點,你可以在詢問前,無限次換邊,然後求最小花費

 

思路:

這個可以直接轉化爲每條邊跑過幾次,然經過多的邊匹配小的權值就好,這就是樹上差分問題了。

不懂樹上差分可以看這:https://www.cnblogs.com/ice-wing/p/7709311.html

 

代碼:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=998244353;
const int maxn=3e5+10;
const ll inf=1e18;
vector<int>e[maxn];
int vis[maxn];
int w[maxn];
int f[maxn][30];
int dep[maxn];
int val[maxn];
int n;
int cs[maxn];
int cnt;
void dfs(int x,int pre)
{
    dep[x]=dep[pre]+1;
    int k=e[x].size();
    for(int i=0;i<k;i++)
    {
        int y=e[x][i];
        if(y==pre)continue;
        f[y][0]=x;
        dfs(y,x);
    }
}
void init()
{
    for(int i=1;(1<<i)<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            f[j][i]=f[f[j][i-1]][i-1];
        }
    }
}
int lca(int u,int v)
{
    if(dep[u]>dep[v])swap(u,v);
    int h=dep[v]-dep[u];
    for(int i=0;(1<<i)<=h;i++)
    {
        if((1<<i)&h)v=f[v][i];
    }
    if(u!=v)
    {
        for(int i=(int)log2(n);i>=0;i--)
            if(f[u][i]!=f[v][i])
            u=f[u][i],v=f[v][i];
        u=f[u][0];
    }
    return u;
}
int dfss(int x,int pre)
{
    int ans=val[x];
    int k=e[x].size();
    for(int i=0;i<k;i++)
    {
        int y=e[x][i];
        if(y==pre)continue;
        ans+=dfss(y,x);
    }
    cs[++cnt]=ans;
    return ans;
}
int main()
{
    scanf("%d",&n);
    cnt=0;
    for(int i=0;i<=n;i++)
    {
        e[i].clear();
        vis[i]=0;
        dep[i]=0;
        cs[i]=0;
    }
    int u,v;
    for(int i=1;i<n;i++)
    {

        scanf("%d%d%d",&u,&v,&w[i]);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1,0);
    init();
    int q;
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d%d",&u,&v);
        val[u]++;val[v]++;
        val[lca(u,v)]-=2;
    }
    dfss(1,0);
    ll ans=0;
    sort(w+1,w+n);
    sort(cs+1,cs+cnt);
    for(int i=1;i<cnt;i++)
    {
        ans+=w[i]*cs[cnt-i];
    }
    printf("%lld\n",ans);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章