(題目鏈結)
給出一棵樹以及m個詢問,可以將樹上一條邊的權值修改為0,求經過這樣的修改之後最長的邊最短是多少。
老早就聽說過這道題了,好像使用樹鏈剖分。
先樹鏈剖分求出每個詢問的路程,最長的最短,可以用二分做。二分最長的邊的大小,也就是最後的答案,問題來了,怎麼判斷這個答案是否可行呢?
我們記錄下所有超出當前答案的詢問的個數p,用d記錄下符合條件的邊比當前二分的答案最大大多少,並給所有詢問的兩端點u,v的sum加上1,給他們的最近公共祖先f的sum減去2。這樣做有什麼用呢?這樣就可以統計每條邊經過了多少次了。
我們通過dfs,每經過一條邊i,就把cnts[i]加上當前節點的sum值,這就代表有多少個點會經過這條邊,回溯的時候更新sum即可。
最後的時候如果存在一條邊被經過的次數正好等於當前詢問數p,並且這條邊的長度大於等於d,那麼就是合法的,否則不合法。
其實這樣的話根本就不用寫樹鏈剖分,dfs一遍就可以記錄兩點間距離了。。。然而樹鏈剖分版不知道為什麼最後uoj上extra test被卡的爆空間了。。好像是爆棧,於是手動開無限棧,mle?!而且讀入優化也gi了,真的鬼畜。。。無奈最後換成dfs版,沒想到tle。。。為什麼bzoj上就能ac捏。
差分的時候計數器陣列cnts開成邊數的空間。
// uoj150#include#include#include#include#include#include#define pragma comment(linker,"/stack:1024000000,1024000000")
#define ll long long
#define inf 2147483640
#define pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
int getint()
while (ch>='0' && ch<='9')
return x*f;
}const int maxn=300010;
struct edge e[maxn<<1];
struct ask q[maxn];
int bin[30],fa[maxn][30],head[maxn],deep[maxn],sum[maxn],d[maxn],cnts[maxn<<1];
int n,m,cnt,num;
void link(int u,int v,int w)
void dfs1(int x)
}int lca(int x,int y)
void dfs(int x)
}bool check(int mid)
dfs(1);
for (int i=1;i<=cnt;i++) if (p==cnts[i] && e[i].w>=d) return 1;
return 0;
}int main()
else l=mid+1;
}printf("%d",ans);
return 0;
}
NOIP 2015 UOJ 150 運輸計畫
公元 2044 年,人類進入了宇宙紀元。l 國有 n 個星球,還有 n 1 條雙向航道,每條航道建立在兩個星球之間,這 n 1條航道連通了 l 國的所有星球。小 p掌管一家物流公司,該公司有很多個運輸計畫,每個運輸計畫形如 有一艘物流飛船需要從 ui號星球沿最快的宇航路徑飛行到 vi號星球去。顯然,...
Luogu2680 NOIp2015 運輸計畫
傳送門 sol 最暴力的做法就是列舉最長鏈上的邊,然後再算一次所有的鏈長,更新 ans 這裡要求最大的最小,容易想到二分答案.對於二分的值 mid 掃一遍所有的鏈,若鏈長小於等於 mid 那麼是合法的不需要處理的.否則,就記錄鏈上所有的邊經過的次數 1 最後找到被經過次數等於鏈長大於 mid 的鏈數...
noip2015 運輸計畫
公元 2044 年,人類進入了宇宙紀元。l 國有 n 個星球,還有 n 1 條雙向航道,每條航道建立在兩個星球之間,這 n 1 條航道連通了 l 國的所有星球。小 p 掌管一家物流公司,該公司有很多個運輸計畫,每個運輸計畫形如 有一艘物流飛船需要從 ui 號星球沿最快的宇航路徑飛行到 vi 號星球去...