P6584 重拳出擊

2022-04-02 14:47:54 字數 1465 閱讀 6617

來給 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 個節點的子樹,所需要切除的最小邊數。為什麼我的不行吶?因為對於乙個新的子節點更新狀態,它能生成多大...