蒟蒻林蔭小複習 克魯斯卡爾重構樹

2022-05-08 06:18:06 字數 3096 閱讀 4771

這是乙個冷門到不能再冷門的東西,至於這東西有什麼用,且聽我慢慢道來。

現在給定一張無向圖,每個點有乙個點權,每條邊有乙個邊權。現在給出許多詢問三元組(x,y,z),要求求出從x出發,只能走邊權不超過y的邊,所能走到邊權第z大的點的點權是多少?(bzoj3551)

如果離線的話,大佬們好像可以用主席樹套樹之類的鬼東西實現,我誠實的說,我不會!!!

克魯斯卡爾大家都會吧,不會右轉幼兒園。

克魯斯卡爾的原理是對每條邊進行排序,然後貪心選取最小的可加入邊。因為克魯斯卡爾所選取的邊一定都是可加入的最小的,因此可以保證,上面問題的答案一定是在最小生成樹上執行得出的。

重構樹就是根據克魯斯卡爾的原理,對每一條邊,並不直接連線到樹上,而是新開乙個替代點,用來和應當連線的部分相接(也有可能乙個圖中的原點和乙個替代點相連,以此取代原點和替代點所代表的兩點的連線)。

那麼這個點的點權就是原圖中兩點間的邊權,因為克魯斯卡爾是從最小的邊權開始加入的,那麼由此構成的重構樹的點權一定是從葉子到根遞增的。

雖然很醜,湊合著看吧,藍筆為點的編號(點權),紫筆為邊權。

那麼所生成的重構樹則如左圖(帶t的點是新生成的替代點,也就是說,原來的點只存在於葉子節點

那這樣是不是就可以發現:在克魯斯卡爾重構樹中,每一顆子樹中任意葉子節點之間的通路中邊權最大值不會超過該子樹根節點的權值?

因為每次被加入的都是權值更大的邊,因此對於替代點而言,點權越小,越處於樹的底部。那麼是不是對於上面的問題就有點想法了?

我們可以先構造出克魯斯卡爾重構樹,然後每次通過樹上倍增找到乙個節點u使得val[u]<=y且val[u]盡可能的大,而且我們是否可以發現乙個神奇的性質,在原圖上每乙個節點,都作為克魯斯卡爾重構樹的乙個且僅乙個葉子節點出現?

那麼我們就可以直接用主席樹解決這個問題了。

因為我們已經求出了節點u,保證以u為根的子樹內所有葉子節點都可以通過最長邊權不超過y的邊到達,那麼是否可以將以某個節點為根的子樹中所有葉子節點的集合視為乙個區間呢?

直接用主席樹維護克魯斯卡爾重構樹的每個葉子節點,然後根據求出的u選擇正確的區間,求值即可。

最後放個**(蒟蒻林蔭寫了一晚上這個東西)

#include#include

#include

#include

using

namespace

std;

int val[100001],fa[100001],bz[100001][26],s[100001],a[100001

];vector

b[100001];//

重構樹int dfn[100001],low[100001],rk[100001

];//

dfn代表每個虛構點的子樹所包含的第乙個實際點,low代表最後乙個

//兩者即可控制出乙個區間

structpe;

pe edge[

500001

];struct

pes;

pes t[

1600001

];int rt[100001

];int

n,m,q,cnt,tot,limt,top,num;

bool

function(pe x,pe y)

int find(int

x)void dfs(int x,int

ff)

else

bz[x][

0]=ff;

for(int i=b[x].size()-1;i>=0;i--)

}void add(int &x,int l,int r,int

p)/*

int query(int b2,int b1,int l,int r,int k)

int mid=(l+r)>>1;

int sum=t[t[b2].rs].sums-t[t[b1].rs].sums;

if(sum>=k)

else

return query(t[b2].ls,t[b1].ls,l,mid,k-sum);}*/

int query(int a,int b,int l,int r,int

k)int

bzeng()

}}int

main()

sort(s+1,s+1+n);

top=unique(s+1,s+1+n)-s-1

;

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

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

sort(edge+1,edge+1+m,function);

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

tot=n;

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

++tot;

fa[tot]=fa[u]=fa[v]=tot;

val[tot]=edge[i].val;

b[tot].push_back(u);

b[tot].push_back(v);

}dfs(tot,0);

bzeng();

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

int lans=0

,a1,a2,a3;

while(q--)

return0;

}

完結撒花!!!

克魯斯卡爾重構樹

處理給出無向圖,會出現重邊,共m條路徑,每條路徑有乙個困難值,q次詢問,求從點x出發只經過困難值小於等於v的路徑,求某個值。克魯斯卡爾重構樹的核心思想是,當新增最小生成樹的邊的時候,不在兩個點之間直接加邊,而是新建節點,讓邊的兩個節點分別成為它的左右兒子節點,然後這個新建的點,就成為整個聯通塊的代表...

克魯斯卡爾重構樹

克魯斯卡爾重構樹就是在用克魯斯卡爾演算法計算最小生成樹時,構造出一棵樹。當題目需要用到最小生成樹時,常常利用重構樹將其轉化為樹上問題。重構過程 在連線兩個點時,將其連向乙個新點,新點的點權為這條邊的邊權。並查集上就把這兩點的父親設為這個新點。這樣我們就維護了一棵從底向上點權遞增的一棵二叉樹。這棵樹具...

蒟蒻林蔭小複習 Splay

首先表示對yyb大佬的崇高敬意雖然大佬根本不知道林蔭是個神馬東西 在這裡學的 yyb大佬的教程!好吧,我回來填坑了!首先宣告一下定義 structp p t 150001 t陣列就是記錄整顆樹的陣列,v代表當前點的權值,ff代表當前點的父親,ch 0,1 分別代表左右子樹 左子樹上的元素小於根,右子...