HDU6074 Phone Call (并查集 LCA)

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 n−1 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(1≤T≤15), denoting the number of test cases.
In each test case, there are 2 integers n,m(1≤n,m≤100000) in the first line, denoting the number of houses and phone lines.
For the next n−1 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(1≤ai,bi,ci,di≤n,1≤wi≤109), 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)]);
    }
}
时间: 2024-10-19 05:51:35

HDU6074 Phone Call (并查集 LCA)的相关文章

hdu6074[并查集+LCA+思维] 2017多校4

看了标答感觉思路清晰了许多,用并查集来维护全联通块的点数和边权和. 用另一个up[]数组(也是并查集)来保证每条边不会被重复附权值,这样我们只要将询问按权值从小到大排序,一定能的到最小的边权和与联通块中的点数. 下面是过程分析.过程中一共运用了两个并查集. [数据]110 31 21 32 42 53 63 74 85 95 109 6 3 1 501 4 2 5 209 10 8 10 40[分析]首先我们将图构建出来我们将m次询问按权值从小到大排序后: 1 4 2 5 209 10 8 10

习题:过路费(kruskal+并查集+LCA)

过路费  [问题描述]在某个遥远的国家里,有 n 个城市.编号为 1,2,3,…,n.这个国家的政府修 建了 m 条双向道路,每条道路连接着两个城市.政府规定从城市 S 到城市 T 需 要收取的过路费为所经过城市之间道路长度的最大值.如:A 到 B 长度为 2,B 到 C 长度为 3,那么开车从 A 经过 B 到 C 需要上交的过路费为 3. 佳佳是个做生意的人,需要经常开车从任意一个城市到另外一个城市,因此 他需要频繁地上交过路费,由于忙于做生意,所以他无时间来寻找交过路费最低 的行驶路线.然

HDU 2586 How far away? Tarjan算法 并查集 LCA

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 23506    Accepted Submission(s): 9329 Problem Description There are n houses in the village and some bidirectional roads connecting them. Every da

[CSP-S模拟测试]:Dash Speed(线段树+并查集+LCA)

题目描述 比特山是比特镇的飙车圣地.在比特山上一共有$n$个广场,编号依次为$1$到$n$,这些广场之间通过$n−1$条双向车道直接或间接地连接在一起,形成了一棵树的结构. 因为每条车道的修建时间以及建筑材料都不尽相同,所以可以用两个数字$l_i,r_i$量化地表示一条车道的承受区间,只有当汽车以不小于$l_i$且不大于$r_i$的速度经过这条车道时,才不会对路面造成伤害. $Byteasar$最近新买了一辆跑车,他想在比特山飙一次车.$Byteasar$计划选择两个不同的点$S,T$,然后在它

hdu-2874 Connections between cities(lca+tarjan+并查集)

题目链接: Connections between cities Time Limit: 10000/5000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others) Problem Description After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, s

Hdu 5458 Stability (LCA + 并查集 + 树状数组 + 缩点)

题目链接: Hdu 5458 Stability 题目描述: 给出一个还有环和重边的图G,对图G有两种操作: 1 u v, 删除u与v之间的一天边 (保证这个边一定存在) 2 u v, 查询u到v的路径上有几条桥. 解题思路: 这个题目有很多次操作,包含查询和删边两类,首先想到的是连通分量加缩点.如果按照顺序来,删边时候求桥就是问题了.所以可以离线处理,然后一边记录答案一边加边缩点. 对于一个图,把连通分量缩成一个点后,这个图就成为了一棵树, 然后深度差就等于桥的数目.查询的时候对于(u, v)

HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

题目大意:给一个N个点M条边的无向图,有Q个询问:1.删掉a.b之间所存在的边:2.询问有多少条边,单独删掉之后a与b不再连通. 思路:脑洞大开. 对于询问,首先想到的就是a与b之间有多少桥(割边),然后想到双连通分量,然而删边是个坑爹的问题,于是我们离线倒着来,把删边变成加边. 双连通分量这种东西呢,其实缩点连起来之后,就是一棵树辣. 然后询问两个点的时候,设根到点x的距离为dep[x],a.b的最近公共祖先为lca(a, b),那么询问query(a, b) = dep[a] + dep[b

【bzoj3362/3363/3364/3365】[Usaco2004 Feb]树上问题杂烩 并查集/树形dp/LCA/树的点分治

题目描述 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样, 图中农场用F1..F7表示, 每个农场最多能在东西南北四个方向连结4个不同的农场.此外,农场只处在道路的两端.道路不会交叉且每对农场间有且仅有一条路径.邻居鲍伯要约翰来导航,但约翰丢了农场的地图,他只得从电脑的备份中修复了.每一条道路的信息如下: 从农场23往南经距离10到达农场17 从农场1往东经距离7到达农

BZOJ 3910 火车 LCA+并查集

题目大意 给出一棵树,起点,和要经过的点的序列,已经经过的点就不用去了,剩下的点按照顺序依次去,问要经过多少条边. 思路 链剖大概应该是可以,不过没试,用了听大爷说的一种神奇的方法. 因为树上经过的点肯定是一段一段的,就想到用并查集将一段合成一个点,每个点最多只能被合一次,这样的话就能保证时间复杂度.查询的时候像链剖一样一段一段往上跳就行了,还要顺便把路径上的所有点缩起来. CODE #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #incl