uoj150 NOIP2015 運輸計畫

2022-05-21 14:51:09 字數 1574 閱讀 1171

(題目鏈結)

給出一棵樹以及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 號星球去...