HDU 6074 Phone Call LCA + 并查集
2017-09-09 21:58
302 查看
Phone Call
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)[align=left][b]Problem Description[/b][/align]
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.
[align=left][b]Input[/b][/align]
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.
[align=left][b]Output[/b][/align]
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.
[align=left][b]Sample Input[/b][/align]
1
5 2
1 2
1 3
2 4
2 5
1 3 2 4 100
2 2 4 2 10
[align=left][b]Sample Output[/b][/align]
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.
[b]题解:[/b]
将所有线路按代价从小到大排序,对于每条线路(a,b,c,d),首先把a到b路径上的点都合并到LCA,再把c到d路径上的点都合并到LCA,最后再把两个LCA合并即可。
设fi表示i点往上深度最大的一个可能不是和 i 在同一个连通块的祖先,每次沿着f跳即可。用路径压缩的并查集维护这个f即可得到优秀的复杂度。
时间复杂度O(mlogm)。
#include <bits/stdc++.h> inline long long read(){long long x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;} using namespace std; typedef long long LL; const int N = 2e5 + 10, inf = 1e9; vector<int > G ; struct ss{int a,b,c,d,cost;}Q ; int cmp(ss s1,ss s2) {return s1.cost < s2.cost;} int sz ,dep ,fa ,son ,indexS,top ,pos ,ff ,f ; void dfs(int u) { int k = 0;sz[u] = 1;dep[u] = dep[f[u]] + 1; for(auto to : G[u]) { if(to == f[u]) continue; f[to] = u; dfs(to); sz[u] += sz[to]; if(sz[to] > sz[k]) k = to; } if(k) son[u] = k; } void dfs(int u,int chain) { int k = 0;pos[u] = ++indexS; top[u] = chain; if(son[u]) dfs(son[u],chain); for(auto to : G[u]) { if(dep[to] > dep[u] && son[u] != to) dfs(to,to); } } int LCA(int x,int y) { while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x,y); x = f[top[x]]; } if(dep[x] > dep[y]) swap(x,y); return x; } LL COST ,CNT ; inline int finds2(int x) {return x == fa[x] ? x:fa[x] = finds2(fa[x]);} inline int finds(int x) {return x == ff[x] ? x:ff[x] = finds(ff[x]);} inline void merges(int x,int y,int c) { int fx = finds2(x); int fy = finds2(y); if(dep[fx] < dep[fy]) swap(fx,fy); if(fx == fy) return; COST[fy] += COST[fx] + c; CNT[fy] += CNT[fx]; fa[fx] = fy; } inline void go(int x,int zu,int c) { while(1) { x = finds(x); if(dep[x] <= dep[zu]) return ; merges(x,f[x],c); ff[x] = f[x]; } } int n,m,T; void init() { for(int i = 0; i <= n; ++i) G[i].clear(),top[i] = 0,son[i] = 0,dep[i] = 0,fa[i] = 0,pos[i] = 0; indexS = 0; } int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); init(); for(int i = 1; i < n; ++i){ int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } dfs(1); dfs(1,1); for(int i = 1; i <= n; ++i) fa[i] = ff[i] = i,CNT[i] = 1,COST[i] = 0; for(int i = 1; i <= m; ++i) scanf("%d%d%d%d%d",&Q[i].a,&Q[i].b,&Q[i].c,&Q[i].d,&Q[i].cost); sort(Q+1,Q+m+1,cmp); for(int i = 1; i <= m; ++i) { int lc = LCA(Q[i].a,Q[i].b); int lb = LCA(Q[i].c,Q[i].d); go(Q[i].a,lc,Q[i].cost); go(Q[i].b,lc,Q[i].cost); go(Q[i].c,lb,Q[i].cost); go(Q[i].d,lb,Q[i].cost); merges(lc,lb,Q[i].cost); //cout<<lc<<" "<<lb<<endl; } printf("%lld %lld\n",CNT[finds2(1)],COST[finds2(1)]); } return 0; }
相关文章推荐
- hdu-6074 Phone Call (LCA+并查集)
- HDU 6074 Phone Call (LCA+并查集, 2017 Multi-Univ Training Contest 4)
- 2017多校第4场 HDU 6074 Phone Call 并查集,LCA
- HDU6074 Phone Call(并查集,lca)
- HDU6074 Phone Call(LCA+并查集)
- hdu 2874 Connections between cities LCA || dfs+并查集
- HDU2874——Connections between cities 详解 (LCA,RMQ,数据结构,dfs序,并查集)
- |hdu 2874|LCA|并查集|Connections between cities
- HDU6074 Phone Call-并查集
- hdu 2586(LCA+并查集)
- HDU 4297 One and One Story 树lca转rmq 并查集维护根节点环
- Hdu 5458 Stability (LCA + 并查集 + 树状数组 + 缩点)
- hdu2874-Connections between cities (LCA/离线tarjan)
- LCA的三种求法 - HDU 2586
- HDU 2120--Ice_cream's world I【并查集, 判断环的个数】
- HDU 4496 D-City 并查集倒排加边
- 【HDU】5156 Harry and Christmas tree 【lca】
- hdu 1272 小希的迷宫 并查集
- hdu 1671 Phone List
- hdu 1558 Segment set(判断线段有交点+并查集)