來給 zrm 大佬的題寫一篇題解。
這題**實現難度不高,但是比較鍛鍊思維,而且應該有不少種解法。著實是一道質量很高的題目。
首先呢,顯然當小 z 向當前節點的一棵子樹走去時,這棵子樹上的 youyou 會與小 z 的距離減 \(2\) 或者減 \(1\)(減 \(1\) 當且僅當小 z 的射程與 youyou 的距離為 \(1\))。而其餘節點上的 youyou 與小 z 的相對距離不會發生變化。
其次,小 z 在一棵子樹上花的所有時間,只和這棵子樹上最深的有 youyou 的節點有關。
所以,小 z 只需要去迎上離出發點最深的 youyou,然後在消滅這只 youyou 後再去迎離當前節點最深的 youyou,其餘的 youyou 一定能在這個過程中被全部消滅。
用類似於求樹的直徑的方法,通過dfs
找到最深 youyou 的深度、最遠的兩隻 youyou 的距離,那麼消滅第一只 youyou 後,這時最深的 youyou 深度就是最遠距離 \(-\) 第一只 youyou 的深度。
時間複雜度 \(\theta(n)\)。
#includeusing namespace std;
const int maxn = 4e5 + 5;
int n, m, x, y, k, t, ans;
struct e b[maxn << 1];
int head[maxn], cnt;
bool vis[maxn];
bool yy[maxn];
int dep1st, id1st, dep2nd, id2nd;
int maxdep, maxid;
void add(int u, int v)
inline int read()
void dfs(int t, int dep)
for(int i = head[t]; i; i = b[i].next) }
int main()
m = read();
while(m--)
k = read(); t = read();
dfs(t, 0);
dep1st = maxdep; id1st = maxid;
memset(vis, 0, sizeof(vis));
maxdep = 0; maxid = 0;
dfs(id1st, 0);
dep2nd = maxdep - dep1st; id2nd = maxid;
dep1st -= k; dep2nd -= k;
if((dep1st) <= 0 && (dep2nd <= 0))
else if((dep2nd <= 0))
else
printf("%d", ans + (dep1st/2) + (dep2nd/2) + (int)(dep2nd & 1) + 1);
} return 0;
}
P1272 重建道路
p1272 重建道路 題意 有一棵n個點的樹,求刪掉最少的邊數,使得其中p個點的子樹和另一部分分離 dp i j 表示編號為i的點周圍組成j個點的樹最少要刪的邊數 初始狀態 dp i 1 連線這個點的邊數 每個點都是點數為1的樹 然後去考慮連線兩個點,使子樹的點數增多。有兩個點數都是1的樹dp i ...
P1272 重建道路
lin klink link 這道題出的其實挺好的 顯然是乙個樹形dpdp dp問題最開始想複雜了 後來發現很簡單 一直以為是n 3做法 我們用dpu k dp dp u,k 表示在以u uu為根的子樹中,剔除k kk個的最小需要切的邊數 那麼初值就是dpu 1 d uu dp du u dpu,1...
P1272 重建道路
一開始狀態定義錯了 所以沒有對qwq,以及有幾個坑qwq 首先 f i j 表示以 i 為根的子樹,切除 j 個節點所需要切除的最小邊數,而我一開始定義的是表示以 i 為根的子樹,切除後生成一顆有 j 個節點的子樹,所需要切除的最小邊數。為什麼我的不行吶?因為對於乙個新的子節點更新狀態,它能生成多大...