BZOJ2238 mst(最小生成樹 樹鏈剖分)

2021-09-10 02:02:57 字數 1705 閱讀 8878

樹剖好題。

首先按題意做出最小生成樹,如果做不出,那麼所有詢問都是"not connected"。

同樣,如果刪的是非生成樹上的邊,對答案不會造成影響,直接輸出最小生成樹的權值即可。

那麼考慮生成樹上的邊被刪的情況:

很明顯,對於乙個環上的所有邊,如果刪掉一條,剩下的點仍然會保持聯通。

所以這個環上的所有邊都是可以互相替代的。

按照這個思路,我們將所有非生成樹上的邊在樹剖的線段樹上打上標記,表示如果dfn[x]~dfn[y]間有邊被拆掉就可以用權值為x的邊進行替換,query的時候如果結果為inf,那麼刪了之後兩個聯通塊是不連通的,輸出"not connected"即可。

注意最後query的時候其實只用做一次,分這條邊是輕邊還是重邊,重邊直接返回即可,輕邊只能返回深度較深的那條鏈的結果。

細節稍多,但好調。

#includeusing namespace std;

const int maxn=1e5+10;

const int maxm=2e5+10;

const int inf=0x3f3f3f3f;

int n,m,cnt,q;

int flag=1;

int ori,on[maxn],on1[maxn];

int fat[maxn];

int head[maxn],depth[maxn],fa[maxn],son[maxn],siz[maxn],top[maxn];

int nxt[maxm],to[maxm],w[maxm];

int dfn[maxn],ys[maxn],tot;

struct edge

void add(int x,int y,int z)

int find(int x)

void kruskal()

} if(sumsiz[son[u]])

son[u]=v; }}

void dfs2(int u,int tp)

}void push_now(int root,int key)

void push_down(int root)

}void build(int root,int l,int r)

void update(int root,int l,int r,int l,int r,int key)

}int query(int root,int l,int r,int l,int r)

}void updatepath(int x,int y,int key)

if(depth[x]swap(x,y);

update(1,1,n,dfn[y]+1,dfn[x],key);

}int querypath(int x,int y)

else

}int main()

kruskal();

if(!flag)

return 0;

} q=read();

dfs1(1,-1),dfs2(1,1);

build(1,1,n);

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

while(q--)

int ans=querypath(cedge[x].from,cedge[x].to);

if(ans==inf)

puts("not connected");

else

cout<}}

最小生成樹(MST)

在帶權圖中,所有的生成樹中邊權的和最小的那棵 或幾棵 被稱為最小生成樹。幾點注意 求最小生成樹使用kruskal演算法。使用並查集處理節點的集合屬性,初始時所有結點屬於只包含其自身的孤立集合。實現 include include using namespace std define n 101 in...

最小生成樹 MST

1 prim演算法 對點進行貪心操作。適合稠密圖 const int m 1005 int vis m 表示該i點是否被選擇 vis i 0 還未被選擇 int map m m map i j 表示i到j的距離 int dis m 1到i的距離和 void prim cout sum 2 krusk...

最小生成樹MST

最小生成樹是在一張無向連通圖中,找到一棵樹,使得其邊的代價之和最小。注 可能存在多個最小生成樹。以邊為展開,將圖中的最小代價邊嘗試加入集合tree中,並且該邊不能與集合tree中的邊形成環,如此迭代,最終得到的集合tree為mst。因此可以採用並集查的方式實現kruskal演算法 以點為展開,將圖中...