1. 程式人生 > >HDU6074 Phone Call (並查集 LCA)

HDU6074 Phone Call (並查集 LCA)

pts edge for each time pic using lars test logs

Phone Call

Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 156 Accepted Submission(s): 67


Problem Description There are n houses in Bytetown, labeled by 1,2,...,n. In each house, there is a person living here. Little Q lives in house 1. There are n1
bidirectional streets connecting these houses, forming a tree structure. In this problem, S(u,v) denotes the house set containing all the houses on the shortest path from house u to house v.

The Bytetown‘s phone line network consists of m different lines. The i-th line can be expressed as 5 integers ai,bi,ci,di,wi
, which means for every two different houses u and v from set S(ai,bi)S(ci,di), u and v can have a phone call costing wi dollars.


技術分享
Picture from Wikimedia Commons


Little Q is now planning to hold a big party in his house, so he wants to make as many as possible people known. Everyone known the message can make several phone calls to others to spread the message, but nobody can leave his house.

Please write a program to figure out the maximum number of people that can join the party and the minimum total cost to reach that maximum number. Little Q should be counted in the answer.
Input The first line of the input contains an integer T(1T15), denoting the number of test cases.
In each test case, there are 2 integers n,m(1n,m100000) in the first line, denoting the number of houses and phone lines.
For the next n1 lines, each line contains two integers u and v, denoting a bidirectional edge between node u and v.
For the next m lines, each line contains 5 integers ai,bi,ci,di,wi(1ai,bi,ci,din,1wi109), denoting a phone line.
Output For each test case, print a single line containing two integers, denoting the maximum number of people that can join the party and the minimum total cost to reach that maximum number. Sample Input 1 5 2 1 2 1 3 2 4 2 5 1 3 2 4 100 2 2 4 2 10 Sample Output 4 210 Hint Step 1 : 1 make a phone call to 2 using line 1, the cost is 100. Step 2 : 1 make a phone call to 3 using line 1, the cost is 100. Step 3 : 2 make a phone call to 4 using line 2, the cost is 10. 【題意】給你一棵樹,然後給你M哥條件,每次給出a,b,c,d,cost,表示從a-->b,c-->d的路徑中的點,可以互相到達,花費是cost,到達具有傳遞性 ,現在問你從1節點最多可以到達哪些節點,最小花費是多少。 【分析】將點集合挨個合並算最小花費,這個過程類似最小生成樹。考慮將花費從小到大排序,設up[i]表示i點往上深度最小的一個可能不是和i在同一個 連通塊的祖先,每次沿著up[i]跳即可。用路徑壓縮的並查集維護這個ff即可得到優秀的復雜度。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define met(a,b) memset(a,b,sizeof a)
#define pb push_back
#define mp make_pair
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 1e5+5500;;
const int M = 160009;
const int mod = 1e9+7;
const double pi= acos(-1.0);
typedef pair<int,int>pii;
int n,m,T;
int parent[N],up[N],cnt[N];
int dep[N],fa[N][20];
ll w[N];
vector<int>edg[N];
struct man{
    int a,b,c,d;
    ll cost;
    bool operator < (const man &e)const {
        return cost<e.cost;
    }
}q[N];
int findFa(int x){
    return parent[x]==x?x:parent[x]=findFa(parent[x]);
}
int findUp(int x){
    return up[x]==x?x:up[x]=findUp(up[x]);
}
void dfs(int u,int f){
    fa[u][0]=f;
    for(int i=1;i<20;i++){
        fa[u][i]=fa[fa[u][i-1]][i-1];
    }
    for(int v : edg[u]){
        if(v==f)continue;
        dep[v]=dep[u]+1;
        dfs(v,u);
    }
}
int LCA(int u,int v){
    int U=u,V=v;
    if(dep[u]<dep[v])swap(u,v);
    for(int i=19;i>=0;i--){
        if(dep[fa[u][i]]>=dep[v]){
            u=fa[u][i];
        }
    }
    if(u==v)return (u);
    for(int i=19;i>=0;i--){
        if(fa[u][i]!=fa[v][i]){
            u=fa[u][i];v=fa[v][i];
        }
    }
    return (fa[u][0]);
}
void Union(int x,int y,ll cost){
    x=findFa(x);y=findFa(y);
    if(x==y)return;
    parent[x]=y;
    cnt[y]+=cnt[x];
    w[y]+=w[x]+cost;
}
void merge(int u,int v,ll cost){
    while(1){
        u=findUp(u);
        if(dep[u]<=dep[v])return;
        Union(u,fa[u][0],cost);
        up[u]=fa[u][0];
    }
}
void solve(man s){
    int lca=LCA(s.a,s.b);
    merge(s.a,lca,s.cost);
    merge(s.b,lca,s.cost);
    lca=LCA(s.c,s.d);
    merge(s.c,lca,s.cost);
    merge(s.d,lca,s.cost);
    Union(s.a,s.c,s.cost);
}
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);met(fa,0);
        for(int i=0;i<=n;i++)parent[i]=up[i]=i,cnt[i]=1,w[i]=0,edg[i].clear();
        for(int i=1,u,v;i<n;i++){
            scanf("%d%d",&u,&v);
            edg[u].pb(v);edg[v].pb(u);
        }
        for(int i=0;i<m;i++){
            scanf("%d%d%d%d%lld",&q[i].a,&q[i].b,&q[i].c,&q[i].d,&q[i].cost);
        }
        sort(q,q+m);
        dep[1]=1;dfs(1,0);
        for(int i=0;i<m;i++)solve(q[i]);
        printf("%d %lld\n",cnt[findFa(1)],w[findFa(1)]);
    }
}

HDU6074 Phone Call (並查集 LCA)