牛客練習賽61 F蘋果樹題解

2022-03-03 22:30:45 字數 2405 閱讀 1968

學了澱粉質有一年多了,期間基本沒用過,又因為當時是直接背的**,導致打比賽的時候對這道題根本無從下手,甚至都沒想到是澱粉質qwq

然後,今天去學了一下澱粉質,發現原理和實現特別簡單,快速碼了個模板後,又去順帶學了下點分樹,就來搞這道題了。。。

這道題,我們看資料範圍,發現成熟度的大小非常的小,所以,我們考慮下如何計算答案。

假設資料隨機,我們把樹減號後,期望樹高是logn。

這樣,我們可以,對於每乙個點,我們算出他的子樹裡面所有點到這個子樹的距離。複雜度\(o(nlogn)\)【每個點最多只有logn個祖先,所以每個點最多被算logn次】

然後,求出這個之後,我們就可以開乙個動態加點線段樹來做了,我們對每個點i開一點動態加點線段樹,裡面每個節點表示的是,i的子樹中,成熟度在l-r的距離i最小的節點到i的距離

同樣使用上面的證明方法,每個點最多被放進logn棵線段樹中,所以,加上線段樹的複雜度就是:\(o(nlog^2n)\)

再考慮1操作,其實和上面存值的操作一樣的。

關於2操作,我們可以求出u的所有祖先(包括u)的子樹中,成熟度為l-r的點到這個點的最小距離(訪問一遍線段樹即可),然後加上u到這個點的距離就行了,最後所有答案取最小再乘2(還要走回去)就是我們要求的答案了~

可能有些人有點疑惑,假如,我們對於u的乙個祖先x,他的子樹中成熟度符合條件的到u距離最小的點到x的路徑中是有可能會走到u到x的路徑的一部分的,這樣的話,我們計算的時候,那部分不就重複計算了嗎?但是,畫個圖我們就會發現,其實如果我們有部分走重了話那麼,我們計算既是x的兒子,又是u的祖先的那個點y時,我們就少走了一段y到x的距離,所以,我們在算y的時候的答案就會算x的時候小,同理,如果y也有重疊的話,另乙個點z就會比y算的小。。。由於我們是取最小,所以最終我們的答案一定沒有重疊部分

然而,我們的做法有乙個前提,就是資料隨機。

如果給出乙個鏈的話,複雜度就會原地**

怎麼辦呢?

這裡,就要用到乙個神奇的東西了——點分樹

點分樹是什麼東西?

我們先把原來的樹的重心x做為根,在把x的各個兒子所在的子樹的重心作為x的兒子。。。一直遞迴下去,最終弄出來的樹就是點分樹。

點分樹很神奇,因為我們是把子樹的重心作為根,所以,最終點分樹的樹高一定是logn級別的

而此題,我們其實並不需要知道我們諸如誰是誰的父親之類的資訊,我們需要知道的只是乙個點到其子樹所有點的距離,而這個東西,我們是可以在構造點分樹時,一遍dfs直接求出來,所以我們可以建乙個樹高為logn的點分樹,再用之前的方法,構造動態開點線段樹就可以解決此題了~

**:

#pragma gcc optimize(3,"inline","ofast")

#includeusing namespace std;

const int n=1e5+1,inf=2e9,m=1e7+1;

struct nodet[n<<1];

struct zxsp[m];

int dis[n][30],dep[n];//i到深度為j的祖先的距離

int fa[n];

int val[n],siz[n],tot,root;

int w[n],las[n],len;

bool vis[n];

int id[n];

inline void add(int u,int v,int w),las[u]=len;

}inline void find_zx(int now,int fu)

}val[now]=max(val[now],tot-siz[now]);

if(val[now]>1;

if(x<=mid)else

}inline void insert(int x,int val)

}inline int find(int now,int l,int r,int lc,int rc)

if(lc<=l&&r<=rc)

int mid=(l+r)>>1,res=inf;

if(lc<=mid)

if(rc>mid)

return res;

}inline int find(int x,int l,int r)

return ans>=inf?-1:ans;

}inline int read()

inline void write(int x)

int main()

for(int i=1;itot=n;

val[root]=inf;

find_zx(1,1);

work(root,0);

for(int i=1;i<=n;++i)

while(m--)elseelse}}

return 0;

}

牛客練習賽67 牛妹的蘋果樹

題意 輸出給定的點序號區間中兩點間距離的最大值 思路 考慮倍增思想,st u i 代表從u號節點開始往後2 i個連續數中的直徑的兩個端點。st u i 一定是由 st u i 1 和 st u 2 i 1 i 1 轉移過來的 思考怎麼轉移,顯然對應6種情況 1.若兩個塊中的直徑的端點倆倆之間不存在l...

牛客練習賽61 a 打怪

題目鏈結 題目描述 你是乙個勇士,現在你準備去森林刷毛球怪,你有兩個屬性 血量,攻擊力 毛球怪也有這兩個屬性。當你遭遇乙隻毛球怪時你們會進入戰鬥,然後你和毛球怪輪流攻擊 你先手 每次使對方的血量減去自己攻擊力的數值,當一方的血量小於等於 0 時死亡。現在你想知道在自己活著的前提下最多殺死幾隻毛球怪。...

牛客練習賽61 A 打怪

你是乙個勇士,現在你準備去森林刷毛球怪,你有兩個屬性 血量,攻擊力 毛球怪也有這兩個屬性。當你遭遇乙隻毛球怪時你們會進入戰鬥,然後你和毛球怪輪流攻擊 你先手 每次使對方的血量減去自己攻擊力的數值,當一方的血量小於等於 0 時死亡。現在你想知道在自己活著的前提下最多殺死幾隻毛球怪。第一行乙個正整數 t...