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

将第 1 条航道改造成虫洞: 则三个计划耗时分别为:11,12,11,故需要花费的时间为 12。

将第 2 条航道改造成虫洞: 则三个计划耗时分别为:7,15,11,故需要花费的时间为 15。

将第 3 条航道改造成虫洞: 则三个计划耗时分别为:4,8,11,故需要花费的时间为 11。

将第 4 条航道改造成虫洞: 则三个计划耗时分别为:11,15,5,故需要花费的时间为 15。

将第 5 条航道改造成虫洞: 则三个计划耗时分别为:11,10,6,故需要花费的时间为 11。

故将第 3 条或第 5 条航道改造成虫洞均可使得完成阶段性工作的耗时最短,需要花费的时间为 11。

 (原题传送门[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)

posted @ 2016-12-03 15:36  阿波罗2003  阅读(283)  评论(0编辑  收藏  举报