题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6074
题意:给你一棵树,然后给你M个条件,每次给出a,b,c,d,cost,表示从a-->b,c-->d的路径中的点,可以互相到达,花费是cost,到达具有传递性 ,现在问你从1节点最多可以到达哪些节点,最小花费是多少。
解法:看着官方题解学的。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long LL;
int T,n,m,parent[maxn],up[maxn],cnt[maxn];
struct FastIO
{
static const int S = 1310720;
int wpos;
char wbuf[S];
FastIO() : wpos(0) {}
inline int xchar()
{
static char buf[S];
static int len = 0, pos = 0;
if (pos == len)
pos = 0, len = fread(buf, 1, S, stdin);
if (pos == len) return -1;
return buf[pos ++];
}
inline LL Lint()
{
int c = xchar();
LL x = 0;
while (c <= 32) c = xchar();
for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
return x;
}
inline int xint()
{
int s = 1, c = xchar(), x = 0;
while (c <= 32) c = xchar();
if (c == '-') s = -1, c = xchar();
for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
return x * s;
}
inline void xstring(char *s)
{
int c = xchar();
while (c <= 32) c = xchar();
for (; c > 32; c = xchar()) * s++ = c;
*s = 0;
}
inline void wchar(int x)
{
if (wpos == S) fwrite(wbuf, 1, S, stdout), wpos = 0;
wbuf[wpos ++] = x;
}
inline void wint(LL x)
{
if (x < 0) wchar('-'), x = -x;
char s[24];
int n = 0;
while (x || !n) s[n ++] = '0' + x % 10, x /= 10;
while (n--) wchar(s[n]);
}
inline void wstring(const char *s)
{
while (*s) wchar(*s++);
}
~FastIO()
{
if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;
}
} io;
//parent[i]表示父亲节点是谁
//up[i]表示i点往上深度最大的一个可能不是和i在同一个连通块的祖先
//cnt[i]表示i所在连通块的点数
LL w[maxn]; //i所在连通块离的距离和
int dep[maxn],fa[maxn][20];
//dep[i]表示i点的深度,fa[i][j]代表i跳2^j的点
vector <int> G[maxn];
struct node{
int a,b,c,d;
LL cost;
bool operator < (const node &rhs) const{
return cost < rhs.cost;
}
}q[maxn];//存下询问,按v值排序
void dfs1(int x, int d, int pre){
dep[x] = d;
fa[x][0] = pre;
for(int i=1; i<20; i++){
fa[x][i] = fa[fa[x][i-1]][i-1];
}
for(int i=0; i<G[x].size(); i++){
int v=G[x][i];
if(v == pre) continue;
dfs1(v, d+1, x);
}
}
int findfa(int x){
if(x==parent[x]) return x;
else return parent[x] = findfa(parent[x]);
}
int findup(int x){
if(x == up[x]) return x;
else return up[x] = findup(up[x]);
}
int LCA(int u, int 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 u, int v, LL cost)
{
u = findfa(u), v = findfa(v);
if(u == v) return;
parent[u] = v;
cnt[v] += cnt[u];
w[v] += w[u] + 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(node 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()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
T = io.xint();
while(T--)
{
n = io.xint(), m = io.xint();
for(int i=0; i<=n; i++) parent[i]=up[i]=i,cnt[i]=1,w[i]=0,G[i].clear();
for(int i=1; i<n; i++){
int u, v;
u = io.xint();
v = io.xint();
G[u].push_back(v);
G[v].push_back(u);
}
for(int i=1; i<=m; i++){
//scanf("%d %d %d %d %lld", &q[i].a, &q[i].b, &q[i].c, &q[i].d, &q[i].cost);
q[i].a = io.xint();
q[i].b = io.xint();
q[i].c = io.xint();
q[i].d = io.xint();
q[i].cost = io.Lint();
}
sort(q+1, q+m+1);
dfs1(1, 1, 0);
for(int i=1; i<=m; i++)
{
solve(q[i]);
}
printf("%d %lld\n", cnt[findfa(1)], w[findfa(1)]);
}
return 0;
}