vijos 运输计划 - 二分答案 - 差分 - Tarjan
Description
公元 2044 年,人类进入了宇宙纪元。L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?
Input
第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。接下来 n−1 行描述航道的建设情况,其中第 i 行包含三个整数 ai,bi 和 ti,表示第 i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。数据保证 1≤ai,bi≤n 且 0≤ti≤1000。接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往 vj号星球。数据保证 1≤ui,vi≤n
Output
输出文件只包含一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。
Sample Input
6 3 1 2 3 1 6 4 3 1 7 4 3 6 3 5 5 3 6 2 5 4 5
Sample Output
11
Hint
(原题传送门[here])
首先需要求LCA,把所有询问的求的LCA和出发点,结束点保存下来。
然后二分答案。判断是否可以把耗时大于它的航线的用时缩短到小于等于二分值。
这个判定就用差分,先在数组中将LCA的值-2,出发点和结束点的值分别+1,从叶节点向上累加。
关于判定就找1个所有需要改的航线都覆盖了的边。并且使耗时的最大值要不超过二分值,这样样就行了。否则说明还会有航线的值大于二分值。
另外注意常数对算法的影响,理论复杂度O(n + m + nlog2L)。(L是树上最长链的长度)
Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cctype> 5 #include<algorithm> 6 #include<cmath> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<stack> 11 #include<vector> 12 using namespace std; 13 #define smin(a, b) a = min(a, b) 14 #define smax(a, b) a = max(a, b) 15 typedef bool boolean; 16 template<typename T> 17 inline void readInteger(T& u){ 18 char x; 19 while(!isdigit((x = getchar()))); 20 for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0'); 21 ungetc(x, stdin); 22 } 23 24 typedef class Edge{ 25 public: 26 int end; 27 int next; 28 int w; 29 Edge(const int end = 0, const int next = 0, const int w = 0):end(end), next(next), w(w){} 30 }Edge; 31 32 typedef class MapManager{ 33 public: 34 int ce; 35 int* h; 36 Edge* edge; 37 MapManager(){} 38 MapManager(int points, int edges):ce(0){ 39 h = new int[(const int)(points + 1)]; 40 edge = new Edge[(const int)(edges + 1)]; 41 memset(h, 0, sizeof(int) * (points + 1)); 42 } 43 inline void addEdge(int from, int end, int w){ 44 edge[++ce] = Edge(end, h[from], w); 45 h[from] = ce; 46 } 47 inline void addDoubleEdge(int from, int end, int w){ 48 addEdge(from, end, w); 49 addEdge(end, from, w); 50 } 51 }MapManager; 52 53 #define m_begin(g, i) (g).h[(i)] 54 #define m_end(g, i) (g).edge[(i)].end 55 #define m_next(g, i) (g).edge[(i)].next 56 #define m_w(g, i) (g).edge[(i)].w 57 58 template<typename T>class Matrix{ 59 public: 60 T *p; 61 int lines; 62 int rows; 63 Matrix():p(NULL){ } 64 Matrix(int lines, int rows):lines(lines), rows(rows){ 65 p = new T[(lines * rows)]; 66 } 67 T* operator [](int pos){ 68 return (p + pos * lines); 69 } 70 }; 71 #define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows) 72 73 typedef class union_found{ 74 public: 75 int *f; 76 union_found():f(NULL) {} 77 union_found(int points) { 78 f = new int[(const int)(points + 1)]; 79 } 80 int find(int x) { 81 if(f[x] != x) return f[x] = find(f[x]); 82 return f[x]; 83 } 84 int& operator [](int pos){ 85 return f[pos]; 86 } 87 }union_found; 88 89 #define BZ_MAX 19 90 91 typedef class query{ 92 public: 93 int from; 94 int end; 95 int minv; 96 int lca; 97 query(const int from = 0, const int end = 0, const int lca = 0, const int minv = 0):from(from), lca(lca), end(end), minv(minv){} 98 boolean operator <(query another) const { 99 return this->minv < another.minv; 100 } 101 102 }query; 103 104 boolean operator <(int val, query a){ 105 return val < a.minv; 106 } 107 int n, q; 108 int cq; 109 int* times; 110 int* up; 111 int* dis; 112 MapManager g; 113 boolean* visited; 114 boolean* enable; 115 query *results; 116 MapManager mq; 117 union_found uf; 118 119 inline void init(){ 120 readInteger(n); 121 readInteger(q); 122 g = MapManager(n, 2 * n); 123 mq = MapManager(n, 2 * q); 124 for(int i = 1, a, b, c; i < n; i++){ 125 readInteger(a); 126 readInteger(b); 127 readInteger(c); 128 g.addDoubleEdge(a, b, c); 129 } 130 for(int i = 1, a, b; i <= q; i++){ 131 readInteger(a); 132 readInteger(b); 133 mq.addDoubleEdge(a, b, 1); 134 } 135 } 136 137 void dfs(int node, int last, int distance){ 138 up[node] = last; 139 dis[node] = distance; 140 for(int i = m_begin(g, node); i != 0; i = m_next(g, i)){ 141 int &e = m_end(g, i); 142 if(e == last) continue; 143 dfs(e, node, m_w(g, i) + distance); 144 } 145 } 146 147 inline void init_dfs(){ 148 up = new int[(const int)(n + 1)]; 149 dis = new int[(const int)(n + 1)]; 150 uf = union_found(n + 1); 151 visited = new boolean[(const int)(n + 1)]; 152 enable = new boolean[(const int)(q * 2 + 1)]; 153 memset(up, 0, sizeof(int) * (n + 1)); 154 memset(enable, true, sizeof(boolean) * (q * 2 + 1)); 155 memset(visited, false, sizeof(boolean) * (n + 1)); 156 dfs(1, 0, 0); 157 } 158 159 int cal_length(int a, int b, int lca){ 160 return dis[a] + dis[b] - (dis[lca] << 1); 161 } 162 163 void tarjan(int node){ 164 uf[node] = node; 165 visited[node] = true; 166 for(int i = m_begin(g, node); i != 0; i = m_next(g, i)){ 167 int& e = m_end(g, i); 168 if(!visited[e]){ 169 tarjan(e); 170 uf[e] = node; 171 } 172 } 173 for(int i = m_begin(mq, node); i != 0; i = m_next(mq, i)){ 174 int& e = m_end(mq, i); 175 if(visited[e] && enable[i]){ 176 int lca = uf.find(e); 177 results[++cq] = query(node, e, lca, cal_length(node, e, lca)); 178 enable[i] = enable[i + ((i & 1) ? (1) : (-1))] = false; 179 } 180 } 181 } 182 183 boolean update(int node, int limit, int maxer, int minx){ 184 for(int j = m_begin(g, node); j != 0; j = m_next(g, j)){ 185 int& e = m_end(g, j); 186 if(e == up[node]) continue; 187 if(update(e, limit, maxer, minx)) return true; 188 times[node] += times[e]; 189 } 190 if(times[node] == limit){ 191 if(maxer - cal_length(node, up[node], up[node]) <= minx){ 192 return true; 193 } 194 } 195 return false; 196 } 197 198 boolean check(int minx){ 199 int counter = 0; 200 int maxer = 0; 201 memset(times, 0, sizeof(int) * (n + 1)); 202 query* it = upper_bound(results + 1, results + q + 1, minx); 203 for(; it != results + q + 1; it++){ 204 times[it->from]++; 205 times[it->end]++; 206 times[it->lca]++; 207 counter++; 208 smax(maxer, it->minv); 209 } 210 return update(1, counter, maxer, minx); 211 } 212 213 inline void solve(){ 214 int l = 0, r; 215 results = new query[(const int)(q + 1)]; 216 tarjan(1); 217 delete[] visited; 218 delete[] uf.f; 219 times = new int[(const int)(n + 1)]; 220 sort(results + 1, results + q + 1); 221 r = results[q].minv; 222 while(l <= r){ 223 int mid = l + ((r - l) >> 1); 224 if(check(mid)) r = mid - 1; 225 else l = mid + 1; 226 } 227 printf("%d", r + 1); 228 } 229 230 int main(){ 231 init(); 232 init_dfs(); 233 solve(); 234 return 0; 235 }
(PS:这道题很神奇,vijos过了,codevs的最后一个点TLE)