BZOJ 4326 NOIP2015 运输计划(树上差分+LCA+二分答案)
4326: NOIP2015 運輸計劃
Time Limit:?30 Sec??Memory Limit:?128 MBSubmit:?1388??Solved:?860
[Submit][Status][Discuss]
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 31 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
Sample Output
11HINT
?
將第 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。
?
?
?
題目鏈接:BZOJ 4326
哇這題居然有權限可以做,真是感動啊……中文題題意就不說了,來西安集訓的這幾天老師介紹了這題,說是二分答案balabala,然后介紹了樹上差分這種東西,差分嘛,我們都知道是利用前綴和來做的,這題如何二分答案?顯然是把所有大于路徑長度大于當前判定答案mid的路徑取出,然后看這些路徑的最大值減去最大可減少的一條邊是否小于等于mid,為什么是交集?我們需要的是需要減少一條邊來讓所有的超出mid的邊均小于等于mid,如果是非交集邊顯然總有至少一條路徑仍然還是大于mid,那么我們如何求這些原路徑長度大于mid交集邊呢?
求邊問題就成了求一些路徑被選出來的所有邊覆蓋過,這里就用到了樹上差分這種東西,對于所有選出來的邊,進行$val_v++$、$val_u++$、$val_{lca(u,v)}-=2$,然后從子節點自下至上統計一個到根節點的前綴和,那么每一個節點的值就是它到父親邊被覆蓋過的次數,但是每一次從兒子DFS到根復雜度很可能會爆啊,這里可以把節點用后序遍歷存下來,使得父節點一定在子節點統計完再累加,就變成$O(n)$的求前綴和復雜度了……。把選邊的過程改成先排序預處理+二分位置居然還慢了一秒,無語了。最后我想說namespace大法好啊,寫起來酷炫又避免了同名函數的尷尬
代碼:
#include <stdio.h> #include <algorithm> #include <cstdlib> #include <cstring> #include <bitset> #include <string> #include <stack> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define fin(name) freopen(name,"r",stdin) #define fout(name) freopen(name,"w",stdout) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); const int N = 300010; struct edge {int to, nxt, t;edge() {}edge(int _to, int _nxt, int _t): to(_to), nxt(_nxt), t(_t) {} } E[N << 1]; int head[N], tot; int sum[N], F[N], D[N << 1], ver[N << 1], ts, fa[N], dp[N << 1][20]; int tim[N], arr[N], sz, cost[N]; int U[N], V[N], LCA[N], Dis[N]; int n, m;void init() {CLR(head, -1);tot = 0;ts = 0;sz = 0; } inline void add(int s, int t, int ti) {E[tot] = edge(t, head[s], ti);head[s] = tot++; } void dfs(int u, int f, int dep, int sumt) {ver[++ts] = u;F[u] = ts;D[ts] = dep;fa[u] = f;tim[u] = sumt;for (int i = head[u]; ~i; i = E[i].nxt){int v = E[i].to;if (v != f){cost[v] = E[i].t;dfs(v, u, dep + 1, sumt + E[i].t);ver[++ts] = u;D[ts] = dep;}}arr[++sz] = u; } namespace RMQ {void init(int l, int r){int i, j;for (i = l; i <= r; ++i)dp[i][0] = i;for (j = 1; l + (1 << j) - 1 <= r; ++j){for (i = l; i + (1 << j) - 1 <= r; ++i){int a = dp[i][j - 1], b = dp[i + (1 << (j - 1))][j - 1];dp[i][j] = D[a] < D[b] ? a : b;}}}int LCA(int u, int v){int l = F[u], r = F[v];if (l > r)swap(l, r);int len = r - l + 1, k = 0;while (1 << (k + 1) <= len)++k;int a = dp[l][k], b = dp[r - (1 << k) + 1][k];return D[a] < D[b] ? ver[a] : ver[b];} } int check(int t) {CLR(sum, 0);int ecnt = 0;int Maxcost = 0;for (int i = 0; i < m; ++i){if (Dis[i] > t){if (Dis[i] > Maxcost)Maxcost = Dis[i];++ecnt;++sum[U[i]];++sum[V[i]];sum[LCA[i]] -= 2;}}for (int i = 1; i <= sz; ++i){int u = arr[i];sum[fa[u]] += sum[u];}int Maxreduce = 0;for (int i = 1; i <= n; ++i)if (sum[i] == ecnt && cost[i] > Maxreduce)Maxreduce = cost[i];return Maxcost - Maxreduce <= t; } int main(void) {int i, a, b, t;while (~scanf("%d%d", &n, &m)){init();for (i = 1; i < n; ++i){scanf("%d%d%d", &a, &b, &t);add(a, b, t);add(b, a, t);}dfs(1, 0, 0, 0);RMQ::init(1, ts);for (i = 0; i < m; ++i){scanf("%d%d", U + i, V + i);LCA[i] = RMQ::LCA(U[i], V[i]);Dis[i] = tim[U[i]] + tim[V[i]] - (tim[LCA[i]] << 1);}int L = 0, R = *max_element(Dis, Dis + m);int ans = 0;while (L <= R){int mid = MID(L, R);if (check(mid)){R = mid - 1;ans = mid;}elseL = mid + 1;}printf("%d\n", ans);}return 0; }轉載于:https://www.cnblogs.com/Blackops/p/7300188.html
總結
以上是生活随笔為你收集整理的BZOJ 4326 NOIP2015 运输计划(树上差分+LCA+二分答案)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入了解Java之虚拟机内存
- 下一篇: Echarts 自定义数据视图