魔法森林 NOI2014

2022-05-27 11:27:16 字數 1866 閱讀 5168

【題目描述】

題目描述又臭又長

簡單來說 有乙個有\(n\)個點,\(m\)條邊的無向圖,每條邊有兩個權值\(a,b\),從點\(u\)走到任意乙個點\(v\)的代價是途經的邊中最大的\(a\)加上最大的\(b\)

求從點\(1\)到點\(n\)的最小代價

【輸入格式】

rt,給你一張圖

【輸出格式】

輸出最小代價。如果無法到達,輸出-1

如果邊權只有乙個,那麼顯然就是建出最小生成樹

但是這裡有兩個 我們可以先以\(a\)為關鍵字給所有邊從小到大排序 然後依次把每條邊加入

這裡就和最小生成樹有些異曲同工之妙相似

假設加入的這條邊是\((u,v)\),如果\(u,v\)還未聯通就直接給它連上

如果已經聯通了 我們就檢查一下現在的\(u\rightarrow v\)這條鏈上面\(b\)最大的一條邊 如果那條邊的\(b\)比\((u,v)\)的\(b\)大 那就把那條邊割掉 把\((u,v)\)這條邊給連上

這個就可以用lct來維護

求\(b\)最大的邊只需要在splay上維護一下 然後split(u,v)就能找到

每次加完邊後 如果\(1\)與\(n\)聯通 就更新一下答案

\(1\rightarrow n\)路徑上最大的\(b\)已知 那最大的\(a\)呢?

最大的\(a\)直接用這次加入的邊的\(a\)即可

因為如果這次加入的邊不在\(1\rightarrow n\)的路徑上 那麼在這條路徑第一次在樹上出現時就應該已經用正確的\(a\)更新過了

複雜度\(o(n\log n)\)

這道題可以不用findroot來判聯通。。。但是懶得寫了

#include #define n 200005 

using namespace std;

inline int read()

struct edge

} e[n];

int ch[n][2], fa[n], mx[n], val[n], tag[n];

#define lson ch[x][0]

#define rson ch[x][1]

inline void pushup(int x)

inline void rev(int x)

inline void pushdown(int x)

}inline bool isroot(int x)

inline void rotate(int x)

int q[n], top;

inline void splay(int x)

rotate(x); }}

inline void access(int x)

} inline void makeroot(int x)

inline void link(int x, int y)

inline void split(int x, int y)

inline int findroot(int x)

inline void cut(int x, int y)

}int n, m, ans;

int main()

sort(e + 1, e + m + 1);

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

for (int i = 1; i <= m; i++) else lk = 0;

} if (lk)

if (findroot(1) == findroot(n))

} printf("%d\n", ans == 0x7fffffff ? -1 : ans);

return 0;

}

NOI2014 魔法森林

為了得到書法大家的真傳,小e同學下定決心去拜訪住在魔法森林中的隱士。魔法森林可以被看成乙個包含個n節點m條邊的無向圖,節點標號為 1 n 邊標號為1 m 初始時小e同學在 1 號節點,隱士則住在 n 號節點。小e需要通過這一片魔法森林,才能夠拜訪到隱士。魔法森林中居住了一些妖怪。每當有人經過一條邊的...

NOI2014 魔法森林

為了得到書法大家的真傳,小 e 同學下定決心去拜訪住在魔法森林中的隱士。魔法森林可以被看成乙個包含 n 個節點 m 條邊的無向圖,節點標號為1,2,3,n,邊標號為 1,2,3,m。初始時小 e 同學在 1 號節點,隱士則住在 n 號節點。小 e 需要通過這一片魔法森林,才能夠拜訪到隱士。魔法森林中...

NOI2014 魔法森林

noi2014 魔法森林 要求a 與 b 的總和最小 可以按a排序 再以b為權值維護一顆樹 lct維護最小生成樹 要解決的問題 將每一條邊變為乙個點 邊權變為點權 舉個栗子 u v有一條邊權為w的邊 怎lct連邊方式為 u new v new的點權為w 不斷維護最小生成樹 如果新加入的邊的 u與v不...