题意:给出一个连通的无向图, 然后找一颗生成树, 生成树满足点1到每个点的书上距离都是原图中的最短路, 然后在满足最短路的条件下, 点1到每个点的树上路径的序列字典序最小
找出这个树之后, 给出K询问树上有K个结点的路径的最大边权值, 以及这样的最大边权值的路径的方案数。
思路:spfa的过程中建树,建好树后点分治。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 31000;
const int MAXM = 61000;
const int INF = 0x3f3f3f3f;
int n, m, k, tot, tot2;
int head[MAXN], head2[MAXN];
struct Edge {
int to, next, w;
} edge[MAXM*2], edge2[MAXN*2];
void addEdge(int u, int v, int w) {
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
void addEdge2(int u, int v, int w) {
edge2[tot2].to = v;
edge2[tot2].w = w;
edge2[tot2].next = head2[u];
head2[u] = tot2++;
}
int pa[MAXN], lex[MAXN], ed[MAXN];
LL d[MAXN];
bool spfa(int start, int n) {
bool vis3[MAXN];
memset(vis3, 0, sizeof(vis3));
for(int i = 1; i <= n; i++) d[i] = INF;
vis3[start] = 1;
d[start] = 0;
queue<int> q;
while(!q.empty()) q.pop();
q.push(start);
while(!q.empty()) {
int u = q.front();
q.pop();
vis3[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next) {
Edge e = edge[i];
int v = e.to;
if(d[v]>d[u]+e.w || d[v]==d[u]+e.w&&lex[u]<lex[v]) {
d[v] = d[u] + e.w;
pa[v] = u;
if(u == 1) lex[v] = v;
else lex[v] = lex[u];
ed[v] = e.w;
if(!vis3[v]) {
vis3[v] = true;
q.push(v);
}
}
}
}
return true;
}
void initTree() {
spfa(1, n);
for(int i = 2; i <= n; i++) {
addEdge2(i, pa[i], ed[i]);
addEdge2(pa[i], i, ed[i]);
}
}
//以上建树部分,以下树分治
int ans, num, root, des[MAXN], bal[MAXN], cnt[MAXN], tim[MAXN], clk;
LL dist[MAXN];
bool vis[MAXN];
int get_size(int cur, int fa) {
int ans = 1;
for(int i = head2[cur]; i != -1 ; i = edge2[i].next) {
int u = edge2[i].to;
if(u==fa || vis[u]) continue;
ans += get_size(u, cur);
}
return ans;
}
void get_root(int cur, int fa, int tot) {
des[cur] = 1;
bal[cur] = 0;
for(int i = head2[cur]; i != -1 ; i = edge2[i].next) {
int u = edge2[i].to;
if(vis[u] || u==fa) continue;
get_root(u, cur, tot);
des[cur] += des[u];
bal[cur] = max(bal[cur], des[u]);
}
bal[cur] = max(bal[cur], tot-des[cur]);
if(bal[cur] < bal[root]) root = cur;
}
void dfs(int cur, int fa, int dep, int w, int op) {
if(!op) {
if(k>=dep && tim[k-dep+1]==clk) {
if(dist[k-dep+1]+w == ans) num += cnt[k-dep+1];
else if(dist[k-dep+1]+w > ans){
ans = dist[k-dep+1]+w;
num = cnt[k-dep+1];
}
}
}
else {
if(tim[dep]!=clk) dist[dep] = w, cnt[dep] = 1, tim[dep]=clk;
else if(dist[dep] < w) dist[dep] = w, cnt[dep] = 1;
else if(dist[dep] == w) cnt[dep]++;
}
if(k<=dep) return;
for(int i = head2[cur]; i != -1 ; i = edge2[i].next) {
int u = edge2[i].to;
if(u==fa || vis[u]) continue;
dfs(u, cur, dep+1, w+edge2[i].w, op);
}
}
void solve(int cur) {
dist[1] = 0;
++clk;
cnt[1] = 1;
tim[1] = clk;
vis[cur] = 1;
for(int i = head2[cur]; i != -1 ; i = edge2[i].next) {
int u = edge2[i].to;
if(vis[u]) continue;
dfs(u, cur, 2, edge2[i].w, 0);
dfs(u, cur, 2, edge2[i].w, 1);
}
for(int i = head2[cur]; i != -1 ; i = edge2[i].next) {
int u = edge2[i].to;
if(vis[u]) continue;
int sz = get_size(u, cur);
if(sz < k) continue;
root = 0; get_root(u, cur, sz);
solve(root);
}
}
void init() {
memset(head, -1, sizeof(head));
memset(head2, -1, sizeof(head2));
memset(vis, 0, sizeof(vis));
memset(tim, 0, sizeof(tim));
clk = ans = num = tot = tot2 = 0;
bal[0] = INF;
}
template<class T>
inline bool read(T &n){
T x = 0, tmp = 1; char c = getchar();
while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
if(c == EOF) return false;
if(c == '-') c = getchar(), tmp = -1;
while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
n = x*tmp;
return true;
}
int main() {
//freopen("input.txt", "r", stdin);
//cout << INF << endl;
int T; cin >> T;
while(T--) {
scanf("%d%d%d", &n, &m, &k);
init();
for(int i = 1, u, v, d; i <= m; i++) {
read(u); read(v); read(d);
addEdge(u, v, d);
addEdge(v, u, d);
}
initTree();
root = 0; get_root(1, 0, n);
solve(root);
printf("%d %d\n", ans, num);
}
return 0;
}