公元 \(2044\) 年,人類進入了宇宙紀元。
公元\(2044\) 年,人類進入了宇宙紀元。
$l $國有 \(n\) 個星球,還有 \(n-1\) 條雙向航道,每條航道建立在兩個星球之間,這 \(n-1\) 條航道連通了 \(l\) 國的所有星球。
小 \(p\) 掌管一家物流公司, 該公司有很多個運輸計畫,每個運輸計畫形如:有一艘物流飛船需要從 \(u_i\) 號星球沿最快的宇航路徑飛行到 \(v_i\) 號星球去。顯然,飛船駛過一條航道是需要時間的,對於航道 \(j\),任意飛船駛過它所花費的時間為 \(t_j\),並且任意兩艘飛船之間不會產生任何干擾。
為了鼓勵科技創新, \(l\) 國國王同意小 \(p\) 的物流公司參與 \(l\) 國的航道建設,即允許小\(p\) 把某一條航道改造成蟲洞,飛船駛過蟲洞不消耗時間。
在蟲洞的建設完成前小 \(p\) 的物流公司就預接了 \(m\) 個運輸計畫。在蟲洞建設完成後,這 \(m\) 個運輸計畫會同時開始,所有飛船一起出發。當這 \(m\) 個運輸計畫都完成時,小 \(p\) 的物流公司的階段性工作就完成了。
如果小 \(p\) 可以自由選擇將哪一條航道改造成蟲洞, 試求出小 \(p\) 的物流公司完成階段性工作所需要的最短時間是多少?
第一行包括兩個正整數 \(n, m\),表示 \(l\) 國中星球的數量及小 \(p\) 公司預接的運輸計畫的數量,星球從 \(1\) 到 \(n\) 編號。
接下來 \(n-1\) 行描述航道的建設情況,其中第 \(i\) 行包含三個整數 \(a_i, b_i\) 和 \(t_i\),表示第 \(i\) 條雙向航道修建在 \(a_i\) 與 \(b_i\)兩個星球之間,任意飛船駛過它所花費的時間為 \(t_i\)。資料保證 \(1 \leq a_i,b_i \leq n\) 且 \(0 \leq t_i \leq 1000\)。
接下來 \(m\) 行描述運輸計畫的情況,其中第 \(j\) 行包含兩個正整數 \(u_j\) 和 \(v_j\),表示第 \(j\) 個運輸計畫是從 \(u_j\) 號星球飛往 \(v_j\)號星球。資料保證 \(1 \leq u_i,v_i \leq 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
對於 \(100\%\) 的資料,\(100 \leq n \leq 300000\),\(1 \leq m \leq 300000\)。
二分答案,樹上亂搞
首先看到題目所求,是求最大值最小化。一下子就發現答案是單調的,那麼二分答案就確定了。那麼二分之後如何\(check\)呢?
那麼一步步來。
當對於所有的路徑做完差分之後再統一做子樹和後,對於每個子樹和為大於 \(mid\) 路徑總數的點,它到父結點的邊一定被這些路徑同時經過,對於這些路徑,我們取 \(max\) 即可。
至於最長的路徑,直接拿最長的路徑減去 \(max\) 並判斷是否小於等於 \(mid\) 即可。
然後這道題就輕鬆 a 掉了!
// luogu-judger-enable-o2
// 開o2是因為有個點極度卡人,目前我已知的人裡只有用樹剖求lca的過掉了......
#include #include #include #include using namespace std;
int n, m, ans; int head[300001],
f[300001][20]; // head陣列用於鏈式前向星,f陣列為倍增陣列
int change[300001], jl[300001],
num[300001]; // change陣列為差分陣列,jl(就是距離的首字母^_^)陣列為樹上字首和,num陣列為子樹和
struct tree k[300001]; //記錄樹上結點資訊
struct node s[300001]; //路徑資訊
struct egde g[600001]; //邊資訊
int cmp(node x, node y)
void read(int &x)
} //快讀
void build(int x)
} //建樹,造出深度,父親結點,樹上字首和的資訊
int dfs(int x)
return num[x];
} //統計子樹和
bool pd(int mid)
while (s[top].lenth > mid && top <= m) top++; //加入需要處理的路徑
top--;
for (int i = 1; i <= top; i++) //差分陣列加減
dfs(1);
int maxx = 0;
for (int i = 1; i <= n; i++)
if (num[i] == top) maxx = max(maxx, jl[i] - jl[k[i].fa]); //取最大值
if (s[1].lenth - maxx <= mid) return true;
return false;
} //判斷mid是否可行
int lca(int a, int b) else
for (int j = 19; j >= 0; j--)
if (k[f[b][j]].deep >= k[a].deep) b = f[b][j];
for (int j = 19; j >= 0; j--)
if (f[a][j] != f[b][j])
if (a == b) return a;
return k[a].fa;
} //倍增求lca
int main() //存邊
k[1].deep = 1;
build(1);
for (int i = 1; i <= n; i++) f[i][0] = k[i].fa;
for (int j = 1; j <= 19; j++)
for (int i = 1; i <= n; i++)
f[i][j] = f[f[i][j - 1]][j - 1]; //倍增陣列處理
for (int i = 1; i <= m; i++) //處理路徑相關資訊
sort(s + 1, s + m + 1, cmp);
int l = 1, r = s[1].lenth;
ans = r;
while (l <= r) else
l = mid + 1;
} //二分答案
cout << ans;
}
NOIP 2015 day2 T3 運輸計畫
time 2018 9 27 題目大意 資料範圍 1 n m 300000 0 v al 1000 time limit 1000ms memory limit 256mb 1 n,m 300000 0 val 1000 text text 1 n m 3 0000 00 v al 1 000tim...
NOIP2015Day2T3 運輸計畫
題解 二分答案。假設列舉到答案是xxx。找出所有長度大於x xx的鏈,那麼這些鏈上必須要放蟲洞,而且必須放在一條所有鏈都經過的邊上,否則必然有一條鏈的長度是大於x xx的。這個直接差分就能求出所有鏈都經過的邊,並且把最長的那條改為蟲洞,看看所有邊是否合法,則可判斷x xx是否可行。應該不是很難吧。比...
noip2015day1t2 資訊傳遞
把每個同學看成乙個點,傳遞關係看成一條邊,點數等於邊數,因此圖由若干個環或環鏈復合邊數等於點數的東西組成,不存在孤立鏈。在圖上,傳遞一輪後,每個點掌握沿邊前乙個點的資訊,傳遞x輪後,任意乙個點恰好掌握沿邊反向前進x條邊的路徑上的所有點的資訊,要聽到自己的資訊,也就是在環上走一圈。這樣就把題目抽象為找...