點此看題
哎,本來能做出來的,考試最後一秒拍出錯了 qwq
qwqqw
q(對拍還是要及時打)
首先題目可以輕易的轉化為求斷掉多少條邊再接上可以使他變成重心,證明可以用微調法,因為如果不是重心的話往某個子樹大小 >n/
2>n/2
>n/
2 移動一點的話距離和顯然會變小,所以一定是重心。
考試時候想到這裡我還沒有看出解法,我先在腦子裡以我們要求的那個點為根建樹,那麼要操作的就是大小 >n/
2>n/2
>n/
2 的那個子樹。原樹的重心在這個子樹裡是特殊的,我們斷開重心的子樹是效果最好的(這裡還有一種特殊的斷法,就是斷開這個點和重心中間那一段,實際上就相當於把重心和他的父親斷開然後接到這個點上面)
那麼我們找到原樹的重心,想辦法批量處理所有點。我們以重心為根建樹,先把重心的子樹插入,然後逐個訪問子樹,特殊插入上述的中間段,然後用資料結構維護一下就行了。
我用的線段樹上二分,時間複雜度 o(n
logn)
o(n\log n)
o(nlogn)
,**是考場上寫的注釋。
#include
const
int m =
2000005
;int
read()
while
(c>=
'0'&& c<=
'9')
return x*f;
}int n,tot,rt,res,f[m]
,siz[m]
,fa[m]
,ans[m]
;int num[
4*m]
,sum[
4*m]
;//線段樹的"邊數"和點數總和,以點數建立的線段樹
struct edge
}e[2
*m];
void
pre(
int u,
int fa)
if(fl && n-siz[u]
<=n/
2) rt=u;
}void
dfs(
int u,
int p)
}void
ins(
int i,
int l,
int r,
int id,
int fl)
void
ask(
int i,
int l,
int r,
int nmsl)
int mid=
(l+r)
>>1;
if(nmsl<=sum[i<<1]
)//左邊的夠
else
//左邊的不夠
ask(i<<1|
1,mid+
1,r,nmsl-sum[i<<1]
);}void
work
(int u,
int rt)
}int
main()
pre(1,
0);//找重心
dfs(rt,0)
;//以中心為根建樹
ins(1,
1,n,1,
1);//插入根
for(
int i=f[rt]
;i;i=e[i]
.next)
//先插入根的子樹
for(
int i=f[rt]
;i;i=e[i]
.next)
for(
int i=
1;i<=n;i++
)printf
("%d\n"
,ans[i]);
}//100,必須要打對拍
LOJ 皇宮看守
題目鏈結 點加權的最小覆蓋 題目說的很清楚,用最少的點覆蓋所有的點。題目給出的是個樹,所以可以用動態規劃來解決。給出如下定義 f i,0 表示i點不放,i可以被父親節點觀察到 f i,1 表示i點不放,i可以被兒子節點觀察到 f i,2 表示i點放,在i處設定警衛 轉移如下 1 由f i,0 定義可...
loj冪方分解
問題描述 任何乙個正整數都可以用2的冪次方表示。例如 137 27 23 20 同時約定方次用括號來表示,即ab 可表示為a b 由此可知,137可表示為 2 7 2 3 2 0 進一步 7 22 2 20 21用2表示 3 2 20 所以最後137可表示為 2 2 2 2 2 0 2 2 2 0 ...
SOL 星際迷航 LOJ
分 類 大 討 論 給定一棵 n 個點的樹,將其複製 m 次得到 m 1 棵樹,依次編號為 0 sim m 記編號為 i 的樹的節點 j 為 i,j 令所有 m 1 棵樹上的邊都是雙向邊,另外對於每個 i in 1,m 指定 a i,b i 連一條有向邊 i 1,a i to i,b i 這樣得到乙...