1714 地殼運動

2022-05-25 04:03:09 字數 2922 閱讀 7540

1714:地殼運動

時間限制: 6000 ms         記憶體限制: 131072 kb

【題目描述】

城市中建立了n

個應急避難所以躲避災害,這些避難所從1~n編號。此外有m條道路連線這些避難所,所有避難所間均可通過這m條道路直接或間接到達。路可以由若干個平行於x或y座標軸的線段組成,所以避難所xi和yi之間的道路可以用(ui,vi)來表示,道路的長度為ui+vi。

由於地殼運動會導致地面拉伸或收縮,可用兩個實數k1,k2描述城市的伸縮程度,此時某條道路的實際長度變為ui×k1+vi×k2。

有若干個獨立的詢問,每次詢問給出k1和k2,

**都希望在此地殼運動前提下,以最小的花費維護其中一些道路,使得只用這些被維護的道路仍能使所有避難所間相互連通。

因為花費與道路的實際總長成正比,所以你需要對每一次詢問求出被維護道路的最短實際總長度。

【輸入】

第一行三個整數n,m,q,分別表示避難所數量、道路數量、詢問數量。

接下來m行每行四個整數xi,yi,ui,vi。xi,yi表示道路連線的兩個避難所編號,ui,vi

意義如上文所述。

最後q行每行兩個實數,表示每次詢問的的k1和k2。

【輸出】

輸出q行,每行乙個實數,表示實際總長度,保留三位小數。

【輸入樣例】

4 8 3

2 1 3 6

3 2 0 7

4 1 7 0

1 4 4 6

2 1 2 7

1 2 2 10

2 2 5 5

4 4 8 9

0.626436771146 0.472537839745

0.977631137354 0.190235819672

0.418883351791 0.221987861358

【輸出樣例】

12.253

9.671

6.878

【提示】

【資料規模及約定】

對於30%的資料,n≤30,m≤3000,q≤3000;

對於另外30%的資料,n≤20,m≤25000,q≤10000;

對於100%的資料,n≤35,m≤25000,q≤200000,1≤xi,yi≤n,0≤ui,vi≤106,k1,k2>0。

【題解】

顯然我們每次詢問需要跑乙個prim求最小生成樹。那麼我們的任務就是快速求出此次詢問時每條邊選用哪個。

可以將x,y相同的所有邊放入乙個vector中分別處理,考慮最優的邊就是min(ui*k1+vi*k2)。

設該邊權值為w=ui*k1+vi*k2。

vi=(k1*ui-w)/k2。

vi=(k1/k2)*ui-w/k2。

按u公升序排列,相同u去v最大值,這就可以使用斜率優化實現處理出對於斜率最優的邊。

將詢問按斜率排序,即可快速查詢。

**如下:

#includeusing

namespace

std;

const

int n=36

;int

n,m,q,siz[n][n],dao[n][n];

double ma[n][n],dis[n],ans[200005

];bool

book[n];

struct

point

};struct

xunwen

wen[

200005

];vector

ve[n][n],st[n][n];

inline

bool

cmp(point x,point y)

inline

bool

cmp2(xunwen x,xunwen y)

inline

intread()

while(isdigit(c))

return x*f;

}inline

double

query(xunwen x)

ma[i][j]=ma[j][i]=x.k1*st[i][j][h].u+x.k2*st[i][j][h].v;

}else ma[i][j]=ma[j][i]=999999999

; memset(book,

0,sizeof

(book));

dis[

1]=0;double daan=0

;

for(int i=2;i<=n;i++) dis[i]=ma[1

][i];

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

return

daan;

}int

main()

for(int i=1;i)

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

if(!ve[i][j].empty())

int h=siz[i][j];

while(siz[i][j]>=2&&1ll*(st[i][j][h-2].v-st[i][j][h-1].v)*(st[i][j][h-1].u-ve[i][j][k].u)

>1ll*(st[i][j][h-2].u-st[i][j][h-1].u)*(st[i][j][h-1].v-ve[i][j][k].v)) h--,siz[i][j]--,st[i][j].pop_back();

siz[i][j]++;

st[i][j].push_back(ve[i][j][k]);}}

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

sort(wen+1,wen+q+1

,cmp2);

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

for(int i=1;i<=q;i++) printf("

%.3f\n

",ans[i]);

}

view code