[樹上倍增+二分答案][NOIP2012]運輸計劃
題目背景
公元 2044 年,人類進入了宇宙紀元。
題目描述
公元 2044 年,人類進入了宇宙紀元。
L 國有 nn 個星球,還有 n-1n−1 條雙向航道,每條航道建立在兩個星球之間,這 n-1n−1 條航道連通了 LL 國的所有星球。
小 P 掌管一家物流公司, 該公司有很多個運輸計劃,每個運輸計劃形如:有一艘物流飛船需要從 u_iui? 號星球沿最快的宇航路徑飛行到 v_ivi? 號星球去。顯然,飛船駛過一條航道是需要時間的,對於航道 jj ,任意飛船駛過它所花費的時間為 t_jtj? ,並且任意兩艘飛船之間不會產生任何幹擾。
為了鼓勵科技創新, L 國國王同意小 P 的物流公司參與 L 國的航道建設,即允許小P 把某一條航道改造成蟲洞,飛船駛過蟲洞不消耗時間。
在蟲洞的建設完成前小 P 的物流公司就預接了 mm 個運輸計劃。在蟲洞建設完成後,這 mm 個運輸計劃會同時開始,所有飛船一起出發。當這 mm 個運輸計劃都完成時,小 P 的物流公司的階段性工作就完成了。
如果小 P 可以自由選擇將哪一條航道改造成蟲洞, 試求出小 P 的物流公司完成階段性工作所需要的最短時間是多少?
輸入輸出格式
輸入格式:
第一行包括兩個正整數 n, mn,m ,表示 L 國中星球的數量及小 P 公司預接的運輸計劃的數量,星球從 11 到 nn 編號。
接下來 n-1n−1 行描述航道的建設情況,其中第 ii 行包含三個整數 a_i, b_iai?,bi? 和 t_iti? ,表示第 ii 條雙向航道修建在 a_iai? 與 b_ibi? 兩個星球之間,任意飛船駛過它所花費的時間為 t_iti? 。數據保證 1 \leq a_i,b_i \leq n1≤ai?,bi?≤n 且 0 \leq t_i \leq 10000≤ti?≤1000 。
接下來 mm 行描述運輸計劃的情況,其中第 jj 行包含兩個正整數 u_juj? 和 v_jvj? ,表示第 jj 個運輸計劃是從 u_juj? 號星球飛往 v_jvj?號星球。數據保證 1 \leq u_i,v_i \leq n1≤ui?,vi?≤n
輸出格式:
輸出文件只包含一個整數,表示小 P 的物流公司完成階段性工作所需要的最短時間。
輸入輸出樣例
輸入樣例:6 3 1 2 3 1 6 4 3 1 7 4 3 6 3 5 5 3 6 2 5 4 5輸出樣例:
11
二分移動所需的時間,在二分出的時間裏用樹上倍增檢驗能否實現看了題解還是調到吐血,最後發現m放在n後面直接讀入了..
代碼:
1 #include<algorithm> 2 #include<cstdio> 3 #include<cstring> 4 5 const int Maxv = 50005; 6 int Book[Maxv], Head[Maxv], f[Maxv][20], st[Maxv][20], Top[Maxv], Tdis[Maxv], q[Maxv], rnum, tail, cnt, n, m; 7 bool lea[Maxv], vis[Maxv], fs; 8 9 struct Node{ 10 int u, v, w, next; 11 }e[Maxv << 2]; 12 13 struct Army{ 14 int Rest, Top; 15 }army[Maxv]; 16 17 int read(){ 18 int x = 0, f = 1; 19 char ch = getchar(); 20 while (ch < ‘0‘ || ch > ‘9‘) { 21 if (ch == ‘-‘) { 22 f = -1; 23 } 24 ch = getchar(); 25 } 26 while (ch >= ‘0‘ && ch <= ‘9‘) { 27 x = x * 10 + ch - ‘0‘; 28 ch = getchar(); 29 } 30 return x * f; 31 } 32 33 void Add_Edge(int u, int v, int w){ 34 cnt++; 35 e[cnt].v = v; 36 e[cnt].w = w; 37 e[cnt].next = Head[u]; 38 Head[u] = cnt; 39 } 40 41 void Add(int u, int v, int w){ 42 Add_Edge(u, v, w); 43 Add_Edge(v, u, w); 44 } 45 46 inline bool Cmp(int a, int b){ 47 return a > b; 48 } 49 inline bool Cmpmin(Army a, Army b){ 50 return a.Rest < b.Rest; 51 } 52 53 inline bool Cmpmax(Army a, Army b){ 54 return a.Rest > b.Rest; 55 } 56 57 void dfs(int u, int father){ 58 for (int i = Head[u]; i; i = e[i].next) { 59 int v = e[i].v; 60 if (v == father) { 61 continue; 62 } 63 f[v][0] = u; 64 st[v][0] = e[i].w; 65 dfs(v, u); 66 } 67 }//預處理倍增 68 69 void RMQ(){ 70 for (int j = 1; j <= 18; j++) { 71 for (int i = 1; i <= n; i++) { 72 f[i][j] = f[ f[i][j - 1] ][j - 1]; 73 st[i][j] = st[i][j - 1] + st[ f[i][j - 1] ][j - 1]; 74 } 75 } 76 }//預處理倍增 77 78 void dfs1(int u, int father, int topf, int dist){ 79 Top[u] = topf; 80 Tdis[u] = dist; 81 bool ft = false; 82 for (int i = Head[u]; i; i = e[i].next) { 83 int v = e[i].v; 84 if (v == father) { 85 continue; 86 } 87 ft = true; 88 dfs1(v, u, topf, dist); 89 } 90 if (!ft) { 91 lea[u] = true; //標記葉子節點 92 } 93 } 94 95 void dfs2(int u, int father){ 96 if (lea[u]) { 97 fs = true; 98 return; 99 } 100 for (int i = Head[u]; i; i = e[i].next) { 101 int v = e[i].v; 102 if (v == father) { 103 continue; 104 } 105 else if (vis[v]) { 106 continue; 107 } 108 dfs2(v, u); 109 if (fs) { 110 return; 111 } 112 } 113 } 114 115 inline bool Look(int v){ 116 fs = false; 117 dfs2(v, f[v][0]); 118 return fs; 119 } 120 121 inline bool judge(int mid){ 122 memset(vis, false, sizeof(vis)); 123 memset(q, 0, sizeof(q)); 124 memset(army, 0, sizeof(army)); 125 rnum = 0; 126 tail = 0; 127 for (int i = 1; i <= m; i++) { 128 int tim = mid; 129 int now = Book[i]; 130 bool syst = false; 131 while (1) { 132 for (int j = 18; j >= 0; j--) { 133 if (f[now][j] && st[now][j] <= tim) { 134 tim -= st[now][j]; 135 now = f[now][j]; //向上跳 136 break; 137 } 138 if (j == 0 || now == 1) { 139 syst = true; 140 break; //停止條件 141 } 142 } 143 if (syst) { 144 break; 145 } 146 } 147 if (now == 1) { 148 army[++rnum].Top = Top[ Book[i] ]; 149 army[rnum].Rest = tim; 150 } 151 else { 152 vis[now] = true; 153 } 154 } 155 std::sort(army + 1, army + m + 1, Cmpmin); 156 for (int i = 1; i <= m; i++) { 157 if (army[i].Rest < Tdis[ army[i].Top ]) { 158 if (!vis[ army[i].Top ] && Look(army[i].Top)) { 159 vis[ army[i].Top ] = true; 160 army[i].Rest = -1; 161 } 162 } 163 } 164 std::sort(army + 1, army + m + 1, Cmpmax); 165 for (int i = Head[1]; i; i = e[i].next) { 166 int v = e[i].v; 167 if (!vis[v] && Look(v)) { 168 q[++tail] = e[i].w; 169 } 170 } 171 std::sort(q + 1, q + tail + 1, Cmp); 172 for (int i = 1; i <= tail; i++) { 173 if (army[i].Rest < q[i]) { 174 return false; 175 } 176 } 177 return true; 178 } 179 180 int main(){ 181 int u, v, w, R = 0, cnt1 = 0, Ans = 0; 182 n = read(); 183 184 for (int i = 1; i < n; i++) { 185 u = read(); 186 v = read(); 187 w = read(); 188 Add(u, v, w); 189 R += w; 190 } 191 dfs(1, 0); 192 for (int i = Head[1]; i; i = e[i].next) { 193 int v = e[i].v; 194 dfs1(v, 1, v, e[i].w); 195 } 196 RMQ(); 197 m = read(); 198 for (int i = 1; i <= m; i++) { 199 Book[i] = read(); 200 } 201 for (int i = Head[1]; i; i = e[i].next) { 202 cnt1++; 203 } 204 if (cnt1 > m) { 205 printf("-1\n"); 206 return 0; 207 } 208 int L = 0; 209 while (L <= R) { 210 int mid = (L + R) >> 1; 211 if (judge(mid)) { 212 Ans = mid; 213 R = mid - 1; 214 } 215 else { 216 L = mid + 1; 217 } 218 } 219 printf("%d\n", Ans); 220 return 0; 221 }
[樹上倍增+二分答案][NOIP2012]運輸計劃