既然是noip的題目,那麼……
意料之中的偷懶不可避免
actually,剛開始看這道題目的時候沒有什麼想法,然後就手賤點開了標籤——樹鏈剖分!!!
於是我果斷就慫了,過了幾天,我現在又才繼續寫,發現好像也不一定需要樹鏈剖分,不過樹鏈剖分比較好寫吧可能。樹鏈剖分我只是看了看,也沒有實現了,好像就是將樹分成幾條鏈,這樣就可以在鏈上用線段樹快速維護出需要的資訊。當然,我還是先不談論這種高深的話題了。
如果等我學了樹鏈剖分之後,我還記得這件事的話,我就填坑。
首先,我們發現可以列舉這個最短距離k,而且還可以二分答案。我經過卡評測之後發現maxr設到2∗
1082 ∗10
8就可以a了。
其次為了好查詢距離,我們可以記錄每個節點到根節點的距離,再記錄每組運輸計畫兩節點的公共祖先,然後就可以利用su
m[x]
+sum
[y]−
2∗su
m[lc
a]s um
[x]+
sum[
y]−2
∗sum
[lca
]快速地算出距離。找出距離大於k的計畫,然後為了使它們的路徑距離變小,應該都需要建立蟲洞,那麼最優當然就是建立在它們的公共交點上,列舉這些交點即可判斷是否可行。
所以關鍵問題就在於如何快速求這個公共交點。對於乙個距離超過k的運輸計畫x->y,記錄路徑對節點的覆蓋次數,利用差分快速修改,ch
a[x]
+=1;
cha[
y]+=
1;ch
a[lc
a]−=
2 cha
[x]+
=1;c
ha[y
]+=1
;cha
[lca
]−=2
。最後在重新dfs一遍就可以獲得每個點的覆蓋次數。由於蟲洞只能改某條航道,那就記錄maxn為最長可能減少的距離,再與最長的路徑maxdis相比較,如果減去之後仍然大於列舉出的k,那麼顯然不成立,否則就可行。依次來二分答案。
貌似這道題還需要一點卡常技巧,我也不知道考noip的時候,能不能卡進去,但至少交到oj上a了。
#include
#include
#include
#include
using
namespace
std;
const
int size=300010,maxr=200000000;
struct dataedge[size<<1];
int n,m,p,head[size],deep[size],pre[size][21];
int s[size],t[size],lca[size],cha[size],sum[size];
template
inline
void read(tp &x)
inline
int max(int x,int y)
inline
void insert(int u,int v,int w)
void dfs(int x,int fa)
}int getlca(int x,int y)
void input()
}void update(int x,int fa)
}bool check(int k)
update(1,0);
for(int i=2;i<=n;i++)
if(cha[i]>=num)
maxn=max(maxn,sum[i]-sum[pre[i][0]]);
if(maxdis-maxn>k)
return
false;
return
true;
}int main()
printf("%d\n",l);
return
0;}
noip2015 運輸計畫
公元 2044 年,人類進入了宇宙紀元。l 國有 n 個星球,還有 n 1 條雙向航道,每條航道建立在兩個星球之間,這 n 1 條航道連通了 l 國的所有星球。小 p 掌管一家物流公司,該公司有很多個運輸計畫,每個運輸計畫形如 有一艘物流飛船需要從 ui 號星球沿最快的宇航路徑飛行到 vi 號星球去...
NOIP2015 運輸計畫
題目鏈結 codevs 4632 題目大意 在一棵 n 節點樹上,有 m個運輸計畫 從ai 到 bi n,m 300000 問 把哪一條樹邊的權值變為0,可以使所有運輸計畫的最大距離最小,輸出這個最大距離的最小值。分析 0.首先要會lca和樹上差分。1.顯然,這道題要求樹上兩點之間的距離,所以要寫l...
noip 2015 運輸計畫
去題面的傳送門 題目的意思是 求將一棵樹上的任意一條邊權賦值為0時,所有航線的最長長度的最小值 想到二分答案 如何驗證?既然我們二分的答案是最長路線,也就是說,在將一條邊權賦值為0之後,所有的路線長度應該都小於等於mid。但是只能刪掉一條邊,所以這條邊是所有刪邊之前長度小於mid的路線的交邊。問題轉...