NOI2014 魔法森林

2021-07-09 09:07:25 字數 3321 閱讀 5885

為了得到書法大家的真傳,小e同學下定決心去拜訪住在魔法森林中的隱士。魔法森林可以被看成乙個包含個n節點m條邊的無向圖,節點標號為 1…

n ,邊標號為1…

m 。初始時小e同學在 

1  號節點,隱士則住在 

n  號節點。小e需要通過這一片魔法森林,才能夠拜訪到隱士。

魔法森林中居住了一些妖怪。每當有人經過一條邊的時候,這條邊上的妖怪就會對其發起攻擊。幸運的是,在 

1  號節點住著兩種守護精靈:a型守護精靈與b型守護精靈。小e可以借助它們的力量,達到自己的目的。

只要小e帶上足夠多的守護精靈,妖怪們就不會發起攻擊了。具體來說,無向圖中的每一條邊 ei

包含兩個權值 ai

與 bi

。若身上攜帶的a型守護精靈個數不少於 ai

,且b型守護精靈個數不少於 bi

,這條邊上的妖怪就不會對通過這條邊的人發起攻擊。當且僅當通過這片魔法森林的過程中沒有任意一條邊的妖怪向小e發起攻擊,他才能成功找到隱士。

由於攜帶守護精靈是一件非常麻煩的事,小e想要知道,要能夠成功拜訪到隱士,最少需要攜帶守護精靈的總個數。守護精靈的總個數為a型守護精靈的個數與b型守護精靈的個數之和。

第1行包含兩個整數 n,

m ,表示無向圖共有 

n  個節點,

m  條邊。

接下來 

m  行,第 i+

1  行包含4個正整數 xi

,yi,

ai,b

i ,描述第 

i  條無向邊。其中 xi

與 yi

為該邊兩個端點的標號,ai

與 bi

的含義如題所述。

注意資料中可能包含重邊與自環。

輸出一行乙個整數:如果小e可以成功拜訪到隱士,輸出小e最少需要攜帶的守護精靈的總個數;如果無論如何小e都無法拜訪到隱士,輸出「

-1 」(不含引號)。

input

4 5

1 2 19 1

2 3 8 12

2 4 12 15

1 3 17 8

3 4 1 17

output
32
explanation

如果小e走路徑1→2→4,需要攜帶 19+

15=34  個守護精靈;

如果小e走路徑1→3→4,需要攜帶 17+

17=34  個守護精靈;

如果小e走路徑1→2→3→4,需要攜帶 19+

17=36  個守護精靈;

如果小e走路徑1→3→2→4,需要攜帶 17+

15=32  個守護精靈。

綜上所述,小e最少需要攜帶 

32  個守護精靈。

input

3 1

1 2 1 1

output
-1
explanation

小e無法從1號節點到達3號節點,故輸出-1。

測試點編號

n

m ai

,bi 12

≤n≤5

0≤m≤

10 1≤

ai,b

i≤10 23

42≤n

≤500

0≤m≤

3000

1≤ai,b

i≤50000

5672≤n

≤5000

0≤m≤

10000

8910112≤

n≤50000

0≤m≤

100000

1≤ai≤30

1≤bi

≤50000

1213

14151≤

ai,b

i≤50000

1617

181920

首先觀察前3個點,直接爆搜不要慫

50分的做法n<=5000 m<=10000肯定存在n^2的做法,我們可以觀察到,排序可以省掉一維,然後每次加邊跑spfa,spfa是可以卡的當然這題資料良心而且時限3s。

繼續觀察11到14個點,a權值很小,肯定可以騙分,我想到的做法是列舉a的權值,然後加邊,這樣最多跑30遍spfa,3s的時限是卡不掉的。

最後我們講正解。聽說這題spfa可以過(資料太良心),觀察到我們排序後每次加b權值,我們要維護1到n的b權值的最大值最小,那果斷最小生成樹了,而a權值已經確定,那我們就可以用lct維護最小生成樹,lct維護邊的方法是在x,y之間加乙個權值為w的點(當然這只是其中一種做法),然後我們要維護最大權值及其編號,加入一條邊的時候,我們先維護更小的生成樹(這樣可以保證1到n的b權值更小),先判斷x,y是否相連,不相連就連線,相連我們就判斷如果w>(x,y之間的最大邊),切掉x,y之間的最大邊然後加x,y這條邊。注意cut的時候一定要把最大點(即邊)先存下來,因為cut一次的時候x,y的最大邊已經改變了,我因為這個查了很久。

廢話不說附上**:

#include#include#include#include#includeusing namespace std;

const int maxx=150010;

int fa[maxx],lc[maxx],rc[maxx],a[maxx],sum[maxx],sum1[maxx];

int tag[maxx],cnt[maxx],tot,ans=maxx;

int n,i,j,k,m;

struct sb;

sb e[maxx];

inline bool rule(sb a,sb b)

inline int isroot(int x)

inline void rev(int x)

inline void putdown(int x)

}inline void pushup(int x)

inline void turn(int x)

inline void splay(int x)

pushup(x);

}inline void lct_access(int x)

}inline void makeroot(int x)

inline void lct_link(int x,int y)

inline void lct_split(int x,int y)

inline void lct_cut(int x,int y)

}inline int lct_check(int x,int y)

int main()

else

} if (lct_check(1,n))

}if (ans==maxx) cout<

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不...

NOI2014 魔法森林

此題可以用spfa,也可以用lct。可spfa跑得比lct快 學習了一下怎麼把邊權變成點權 新建乙個點表示邊,這個點的點權就是邊權值 原來的點的權值為0 根據題目需要可以為其他值 新增一條邊時,連線兩端的點 刪除一條邊時,需要找到這條邊對應的點編號,兩端刪除 include include incl...