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最大值,這就可以使用斜率優化實現處理出對於斜率最優的邊。
將詢問按斜率排序,即可快速查詢。
**如下:
#includeusingview codenamespace
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]);
}