题目大意:
给出一个连通的无向图, 然后找一颗生成树, 生成树满足点1到每个点的书上距离都是原图中的最短路, 然后在满足最短路的条件下, 点1到每个点的树上路径的序列字典序最小
找出这个树之后, 给出K询问树上有K个结点的路径的最大边权值, 以及这样的最大边权值的路径的方案数
大致思路:
首先spfa取得所有的1到其他点的最短距离
然后按照字典序进行dfs找出最短路径树
之后就是裸的树分治的问题了
用dis[i]表示i个结点的路径的最大长度, 用一个pre相加表示是否是当前层的子树的结果
代码如下:
Result : Accepted Memory : 7208 KB Time : 908 ms
/* * Author: Gatevin * Created Time: 2015/10/14 19:53:35 * File Name: Sakura_Chiyo.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; #define maxn 30010 int Test; int n, m, K; vector<pair<int, int> > T[maxn];//找出来的树 vector<pair<int, int> > G[maxn];//原图 int del[maxn]; int root; int num; int mx[maxn]; int size[maxn]; int mi; void dfs_size(int now, int father) { size[now] = 1; mx[now] = 0; for(int i = 0, sz = T[now].size(); i < sz; i++) { int v = T[now][i].first; if(v != father && !del[v]) { dfs_size(v, now); size[now] += size[v]; if(size[v] > mx[now]) mx[now] = size[v]; } } } void dfs_root(int r, int now, int father) { if(size[r] - size[now] > mx[now]) mx[now] = size[r] - size[now]; if(mx[now] < mi) mi = mx[now], root = now; for(int i = 0, sz = T[now].size(); i < sz; i++) { int v = T[now][i].first; if(v != father && !del[v]) dfs_root(r, v, now); } } bool vis[maxn]; int d[maxn]; const int inf = 1e9; void spfa()//跑点1到其他所有点的最短距离为d[] { queue<int> Q; Q.push(1); memset(vis, 0, sizeof(vis)); fill(d, d + n + 1, inf); vis[1] = 1, d[1] = 0; while(!Q.empty()) { int now = Q.front(); Q.pop(); vis[now] = 0; for(int i = 0, sz = G[now].size(); i < sz; i++) { int v = G[now][i].first; if(d[v] > d[now] + G[now][i].second) { d[v] = d[now] + G[now][i].second; if(!vis[v]) vis[v] = 1, Q.push(v); } } } } void getTree(int now) { for(int i = 0, sz = G[now].size(); i < sz; i++) if(d[now] + G[now][i].second == d[G[now][i].first] && !vis[G[now][i].first]) { vis[G[now][i].first] = 1; T[now].push_back(G[now][i]); T[G[now][i].first].push_back(make_pair(now, G[now][i].second)); getTree(G[now][i].first); } } #define count motherfuck lint dis[maxn];//dis[i]表示经过i个结点的路径最长的长度 int count[maxn];//count[i]表示经过i个结点的路径最长的方案数 int ans;//点数为K个点路径最大长度 int cnt;//cnt表示dis[K]的答案方案数 lint pre = 0; lint bit = 4e8; void get(int now, int father, int num, lint dep, int flag)//num表示经过点数,dep表示到根节点距离 { num++; if(num >= K) return; if(flag == 0) { if(dis[K - num] >= pre) { if(ans < (dis[K - num] - pre) + dep) ans = dis[K - num] - pre + dep, cnt = count[K - num]; else if(ans == (dis[K - num] - pre) + dep) cnt += count[K - num]; } } else { if(dis[num] >= pre) { if(dis[num] < pre + dep) { dis[num] = pre + dep; count[num] = 1; } else if(dis[num] == pre + dep) count[num]++; } else dis[num] = pre + dep, count[num] = 1; } for(int i = 0, sz = T[now].size(); i < sz; i++) { int v = T[now][i].first; if(!del[v] && v != father) get(v, now, num, dep + T[now][i].second, flag); } } void dfs(int now) { mi = n; dfs_size(now, 0); dfs_root(now, now, 0); del[root] = 1; pre += bit; dis[1] = pre; count[1] = 1; for(int i = 0, sz = T[root].size(); i < sz; i++) { int v = T[root][i].first; if(!del[v]) { get(v, root, 0, (lint)T[root][i].second, 0); get(v, root, 1, (lint)T[root][i].second, 1); } } int tmpRoot = root; for(int i = 0, sz = T[tmpRoot].size(); i < sz; i++) { int v = T[tmpRoot][i].first; if(!del[v]) dfs(v); } } void solve() { //pre = 0; //memset(dis, 0, sizeof(dis)); spfa(); memset(vis, 0, sizeof(vis)); vis[1] = 1; getTree(1);//把树找出来 ans = 0; cnt = 0; memset(del, 0, sizeof(del)); dfs(1); printf("%d %d\n", ans, cnt); } int main() { scanf("%d", &Test); while(Test--) { scanf("%d %d %d", &n, &m, &K); for(int i = 0; i <= n; i++) G[i].clear(), T[i].clear(); int u, v, w; for(int i = 0; i < m; i++) { scanf("%d %d %d", &u, &v, &w); G[u].push_back(make_pair(v, w)); G[v].push_back(make_pair(u, w)); } for(int i = 1; i <= n; i++) sort(G[i].begin(), G[i].end()); solve(); } return 0; } /* 2 2 1 2 1 2 3 */