題目鏈結
現在數列的每一項就是子樹的大小。
也就是說,如果我們能夠盡量多地讓重兒子內部相互抵消(假設最多抵消剩\(x\) 個節點,那麼可以保留的節點就是 (\(x+2k+1\))),以至於重兒子剩餘的大小 \(\le \frac\) 且保持最大或最大-1(如果只有兩棵子樹,且初始次大子樹比最大子樹小1不會影響討論),就可以讓結果變得至多為 1 了。
發現這變成了乙個子問題,所以記狀態 \(f_u\) 表示在 \(u\) 進行一系列抵消後最少剩下多少節點。轉移就比較顯然了。
對於不止查詢一號點的情況,給每個點記個最大和次大的兒子, dfs 到 \(u\) 時把路徑上的點看成乙個點即可。
時間複雜度 \(o(n)\) 。
#includeusing namespace std;
typedef long long ll;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
#define re(x) memset(x, 0, sizeof x)
inline int gi()
while(isdigit(ch))
return x * f;
}template inline bool max(t &a, t b)
template inline bool min(t &a, t b)
const int n = 1e5 + 7, inf = 0x3f3f3f3f;
int n, w, t;
int ans[n], dep[n];
vectorg[n];
struct data data(int son, int f):son(son), f(f){}
bool operator <(const data &rhs) const
bool operator ==(const data &rhs) const
}f[n][2], g[n];
void add(int a, int b)
void dfs1(int u, int fa) else if(f[u][1] < g[v])
g[u].son += g[v].son;
} if(f[u][0].son) else g[u].f = 0;
}void dfs2(int u, int fa, data mx)
for(auto v:g[u]) if(v ^ fa)
}int main()
dfs1(1, 0);
dfs2(1, 0, data(0, inf));
if(w == 3)
printf("%d\n", ans[1] == 0);
else
rep(i, 1, n) printf("%d", ans[i] == 0);
puts("");
} return 0;
}
LOJ2330 清華集訓2017 榕樹之心
loj 感性理解一下,榕樹之心最後要停在乙個節點就是要使得它的不同子樹作用效果互相抵消,而要想使其最後停在乙個點 x 的最大困難就是如何消除重兒子的影響最好辦法就是微笑著去面對它 我們要想辦法量化這乙個過程。令 cnt i 表示 i 子樹能自行消化的對數,siz i 表示 i 子樹的大小,son i...
洛谷P4228 清華集訓2017 榕樹之心
先只考慮根節點是否合法。發現兩個來自不同子樹的點可以消去,那麼只需判定所有點能否兩兩消去,使心停留在根節點即可。發現其可以轉化為乙個模型 有若干個集合,每個集合內有若干個點,每次可以消去兩個來自不同集合的點。設集合點數總和為 sum 最大集合點數為 max 得 sum max geqslant ma...
清華集訓2017模擬 ces
首先把用tajan把橋邊全部找出來,橋邊會把圖分成若干個雙聯通分量。把每個雙聯通分量並成乙個點,橋邊作為邊,這會構成一棵樹。顯然,對於每個詢問加k條邊最多能去掉多少條橋邊,就是用k條簡單路徑去覆蓋這棵樹,最多能覆蓋多少條邊。有乙個很優的貪心,把k按1 q做,每次找到樹的直徑,答案加上直徑的長度,把直...