Luogu3942 將軍令

原題鏈接:https://www.luogu.org/problemnew/show/P3942

將軍令

題目背景

pdf題面和大樣例鏈接:http://pan.baidu.com/s/1cawM7c 密碼:xgxv

 歷史/落在/贏家/之手 
 至少/我們/擁有/傳說 
 誰說/敗者/無法/不朽 
 拳頭/只能/讓人/低頭 
 念頭/卻能/讓人/擡頭 
 擡頭/去看/去愛/去追 
 你心中的夢   
題目描述

又想起了四月。

如果不是省選,大家大概不會這麼輕易地分道揚鑣吧? 只見一個又一個昔日的隊友離開了機房。

憑君莫話封侯事,一將功成萬骨枯。

夢裏,小 F 成了一個給將軍送密信的信使。

現在,有兩封關乎國家生死的密信需要送到前線大將軍帳下,路途兇險,時間緊迫。小 F 不因爲自己的禍福而避趨之,勇敢地承擔了這個任務。

不過,小 F 實在是太粗心了,他一不小心把兩封密信中的一封給弄掉了。

小 F 偷偷打開了剩下的那封密信。他 發現一副十分詳細的地圖,以及幾句批文——原來 這是戰場周圍的情報地圖。他仔細看後發現,在這張地圖上標記了 n 個從 1 到 n 標號的 驛站,n − 1 條長度爲 1 裏的小道,每條小道雙向連接兩個不同的驛站,並且驛站之間可以 通過小道兩兩可達。

小 F 仔細辨認着上面的批註,突然明白了丟失的信的內容了。原來,每個驛站都可以駐 扎一個小隊,每個小隊可以控制距離不超過kk裏的驛站。如果有驛站沒被控制,就容易產 生危險——因此這種情況應該完全避免。而那封丟失的密信裏,就裝着朝廷數學重臣留下的 精妙的排布方案,也就是用了最少的小隊來控制所有驛站。

小 F 知道,如果能計算出最優方案的話,也許他就能夠將功贖過,免於死罪。他找到了 你,你能幫幫他嗎? 當然,小 F 在等待你的支援的過程中,也許已經從圖上觀察出了一些可能會比較有用的 性質,他會通過一種特殊的方式告訴你。

輸入輸出格式
輸入格式:

從標準輸入中讀入數據。

輸入第11行一個正整數n,k,tn,k,t,代表驛站數,一支小隊能夠控制的最遠距離,以及特殊性質所代表的編號。關於特殊性質請參照數據範圍。

輸入第22行至第nn行,每行兩個正整數ui,viu_i ,v_i,表示在uiu_iviv_i間,有一條長度爲 一里的小道。

輸出格式:

輸出到標準輸出中。

輸出一行,爲最優方案下需要的小隊數。

輸入輸出樣例
輸入樣例#1:

4 1 0
1 2
1 3
1 4

輸出樣例#1:

1

輸入樣例#2:

6 1 0
1 2
1 3
1 4
4 5
4 6

輸出樣例#2:

2

說明
【樣例 1 說明】

如圖。由於一號節點到周圍的點距離均是 1,因此可以控制所有驛站。

【樣例 2 說明】

如圖,和樣例 1 類似。

子任務會給出部分測試數據的特點。如果你在解決題目中遇到了困難,可以嘗試只解 決一部分測試數據。

關於tt的含義如下: t=0t = 0:該測試點沒有額外的特殊性質; t=1t = 1:保證最多88個點的所連接的小道超過11條;t=2t = 2:保證所有點到11號點的距離不超過22

每個測試點的數據規模及特點如下表

題解

可以使用消防站的設立的思路,從維護爺爺變成維護kk級祖先,複雜度O(nk)O(nk)

不過還有一種更優秀的O(n)O(n)做法,我們維護對於每個點向下離自己最遠的沒有覆蓋的點的距離,如果該點有一支小隊,距離爲k1-k-1,合併子樹信息時,如果最小值+最大值<0,說明有小隊可以覆蓋這個點,該點的值爲最小值+1,反之爲最大值+1,噹噹前點值大於kk時,設立小隊。

代碼
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
int head[M],nxt[M<<1],to[M<<1],dis[M],ans,cnt,n,k;
void add(int f,int t){nxt[++cnt]=head[f],head[f]=cnt,to[cnt]=t;}
void dfs(int f,int v)
{
    int mx=0,mn=M;
    for(int i=head[v];i;i=nxt[i])if(to[i]!=f)dfs(v,to[i]),mx=max(mx,dis[to[i]]+1),mn=min(mn,dis[to[i]]+1);
    dis[v]=(mx+mn<0?mn:mx);
    if(dis[v]>=k)dis[v]=-k-1,++ans;
}
void in(){scanf("%d%d%*d",&n,&k);for(int i=1,a,b;i<n;++i)scanf("%d%d",&a,&b),add(a,b),add(b,a);}
void ac(){dfs(0,1);if(dis[1]>=0)++ans;printf("%d",ans);}
int main(){in(),ac();}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章