1. 程式人生 > >HYSBZ - 4016 最短路徑樹問題 點分治 + 最短路徑最小字典序

HYSBZ - 4016 最短路徑樹問題 點分治 + 最短路徑最小字典序

題目傳送門

題解:首先對於給定的圖,需要找到那些從1好點出發然後到x號點的最短路, 如果有多條最短路就要找到字典序最小的路,這樣扣完這些邊之後就會有一棵樹。然後再就是很普通的點分治了。

對於扣邊這個問題, 我們先跑一遍最短路,這樣就可以得到1號點到其他的點的距離。

然後在跑一遍dfs, 我們在跑dfs找路的時候, 可以通過 d[u] + ct[i] == d[v] 來判斷是不是最短路是否可以走這條邊, 然後我們再從所有可能邊中的最小編號出發,這樣我們就能保證字典序最小了。

程式碼:

  1 #include<bits/stdc++.h>
  2 using
namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define lch(x) tr[x].son[0] 12
#define rch(x) tr[x].son[1] 13 #define max3(a,b,c) max(a,max(b,c)) 14 #define min3(a,b,c) min(a,min(b,c)) 15 typedef pair<int,int> pll; 16 const int inf = 0x3f3f3f3f; 17 const LL INF = 0x3f3f3f3f3f3f3f3f; 18 const LL mod = (int)1e9+7; 19 const int N = 3e4 + 100; 20 vector<pll> vc[N];
21 int d[N]; 22 void dij(){ 23 memset(d, inf, sizeof(d)); 24 priority_queue<pll, vector<pll>, greater<pll> > q; 25 d[1] = 0; 26 q.push(pll(0,1)); 27 int x, dd, v, ct; 28 while(!q.empty()){ 29 x = q.top().se, dd = q.top().fi; 30 q.pop(); 31 if(dd != d[x]) continue; 32 for(int i = 0; i < vc[x].size(); ++i){ 33 v = vc[x][i].fi , ct = vc[x][i].se; 34 if(d[v] > d[x] + ct){ 35 d[v] = d[x] + ct; 36 q.push(pll(d[v], v)); 37 } 38 } 39 } 40 return; 41 } 42 int vis[N]; 43 int head[N], to[N<<2], val[N<<2], nt[N<<2], tot = 0; 44 void add(int u, int v, int ct){ 45 to[tot] = v; 46 val[tot] = ct; 47 nt[tot] = head[u]; 48 head[u] = tot++; 49 return ; 50 } 51 void dfs(int u){ 52 vis[u] = 1; 53 int v, dd; 54 for(int i = 0; i < vc[u].size(); i++){ 55 v = vc[u][i].fi, dd = vc[u][i].se; 56 if(vis[v] || d[v] != d[u] + dd) continue; 57 add(u, v, dd); 58 add(v, u, dd); 59 dfs(v); 60 } 61 return ; 62 } 63 int sz[N]; 64 int rt, minval; 65 int n, m, k; 66 void get_rt(int o, int u, int num){ 67 sz[u] = 1; 68 int v; 69 int maxval = 0; 70 for(int i = head[u]; ~i; i = nt[i]){ 71 v = to[i]; 72 if(v == o || vis[v]) continue; 73 get_rt(u, v, num); 74 sz[u] += sz[v]; 75 maxval = max(maxval, sz[v]); 76 } 77 if(o) maxval = max(maxval, num - sz[u]); 78 if(maxval < minval){ 79 minval = maxval; 80 rt = u; 81 } 82 } 83 int fans = 0, fcnt = 0; 84 int cnt[N], dis[N]; 85 void Update(int vval, int num){ 86 if(fans == vval) fcnt += num; 87 else if(fans < vval) fans = vval, fcnt = num; 88 return ; 89 } 90 void Dfs(int o, int u, int w, int num){ 91 sz[u] = 1; 92 if(num == k-1) 93 Update(w, 1); 94 if(k >= num && dis[k-num]){ 95 Update(w+dis[k-num], cnt[k-num]); 96 } 97 for(int i = head[u]; ~i; i = nt[i]){ 98 int v = to[i]; 99 if(v == o || vis[v]) continue; 100 Dfs(u, v,w+val[i], num+1); 101 sz[u] += sz[v]; 102 } 103 return ; 104 } 105 void Change(int o, int u, int w, int num, int op){ 106 if(num >= k) return ; 107 if(op == 1) { 108 if(dis[num+1] < w) dis[num+1] = w, cnt[num+1] = 1; 109 else if(dis[num+1] == w) cnt[num+1]++; 110 } 111 else dis[num+1] = cnt[num+1] = 0; 112 for(int i = head[u]; ~i; i = nt[i]){ 113 int v = to[i]; 114 if(v == o || vis[v]) continue; 115 Change(u, v, w+val[i], num+1, op); 116 } 117 return ; 118 } 119 void solve(int x, int num){ 120 if(num <= 1) return ; 121 minval = inf; 122 get_rt(0, x, num); 123 vis[rt] = 1; 124 int v; 125 for(int i = head[rt]; ~i; i = nt[i]){ 126 v = to[i]; 127 if(vis[v]) continue; 128 Dfs(0, v, val[i], 1); 129 Change(0, v, val[i], 1, 1); 130 } 131 for(int i = head[rt]; ~i; i = nt[i]){ 132 v = to[i]; 133 if(vis[v]) continue; 134 Change(0, v, val[i], 1, 0); 135 } 136 for(int i = head[rt]; ~i; i = nt[i]){ 137 v = to[i]; 138 if(vis[v]) continue; 139 solve(v, sz[v]); 140 } 141 return ; 142 } 143 int main(){ 144 int u, v, w; 145 memset(head, -1, sizeof(head)); 146 scanf("%d%d%d", &n, &m, &k); 147 for(int i = 1; i <= m; i++){ 148 scanf("%d%d%d", &u, &v, &w); 149 vc[u].pb(pll(v,w)); 150 vc[v].pb(pll(u,w)); 151 } 152 dij(); 153 dfs(1); 154 memset(vis, 0, sizeof(vis)); 155 solve(1, n); 156 printf("%d %d", fans, fcnt); 157 return 0; 158 }
View Code