1. 程式人生 > >bzoj2395 [Balkan 2011]Timeismoney

bzoj2395 [Balkan 2011]Timeismoney

答案 怎麽 三角形面積 cond In sed ++ 分割 truct

題意:每條邊有兩個權值a,b,求圖的最小二元和乘積生成樹(即該樹的sum_a*sum_b最小)。

標程:

技術分享圖片
 1 #include<bits/stdc++.h>
 2 #define P pair<ll,ll>
 3 #define fir first
 4 #define sec second
 5 using namespace std;
 6 typedef long long ll;
 7 int read()
 8 {
 9    int x=0,f=1;char ch=getchar();
10    while (ch<0||ch>9) {if
(ch==-) f=-1;ch=getchar();} 11 while (ch>=0&&ch<=9) x=(x<<1)+(x<<3)+ch-0,ch=getchar(); 12 return x*f; 13 } 14 const int N=10005; 15 int f[N],n,m; 16 ll ans,qa,qb; 17 struct node{ll u,v,a,b,w;}e[N]; 18 int find(int x){return x==f[x]?x:f[x]=find(f[x]);} 19 bool cmp_a(const
node &A,const node &B){return A.a<B.a;} 20 bool cmp_b(const node &A,const node &B){return A.b<B.b;} 21 bool cmp_w(const node &A,const node &B){return A.w<B.w;} 22 ll chaji(P A,P B,P C){return (B.fir-A.fir)*(C.sec-A.sec)-(B.sec-A.sec)*(C.fir-A.fir);} 23 P mst() 24 { 25
ll s1=0,s2=0; 26 for (int i=1;i<=n;i++) f[i]=i; 27 for (int i=1;i<=m;i++) 28 if (find(e[i].u)!=find(e[i].v)) 29 f[find(e[i].u)]=find(e[i].v),s1+=e[i].a,s2+=e[i].b; 30 ll t=s1*s2; 31 if (t<ans) ans=t,qa=s1,qb=s2; 32 else if (t==ans&&s1<qa) qa=s1,qb=s2; 33 return P(s1,s2); 34 } 35 void solve(P A,P B) 36 { 37 for (int i=1;i<=m;i++) 38 e[i].w=(B.fir-A.fir)*e[i].b-(B.sec-A.sec)*e[i].a; 39 sort(e+1,e+m+1,cmp_w);P C=mst(); 40 if (chaji(A,B,C)>=0) return; 41 solve(A,C);solve(C,B); 42 } 43 int main() 44 { 45 n=read();m=read();ans=1ll<<60; 46 for (int i=1;i<=m;i++) e[i].u=read()+1,e[i].v=read()+1,e[i].a=read(),e[i].b=read(); 47 sort(e+1,e+m+1,cmp_a);P A=mst(); 48 sort(e+1,e+m+1,cmp_b);P B=mst(); 49 solve(A,B); 50 printf("%lld %lld\n",qa,qb); 51 return 0; 52 }
View Code

題解:數形結合+凸包

把每棵生成樹按照(sum_a,sum_b)映射到坐標系上,基於乘積的反比例函數性質,動態維護下凸包。

具體地,先找到sum_a最小的點A和sum_b最小的點B,連邊,在這條線的下方找到一個距離這條直線最遠的點C。那麽△ABC中的點一定不及三個端點的答案小。繼續AC連邊和CB連邊找下方點,分治。並對端點統計。

難點在於最遠點怎麽求?轉換成三角形面積最大,用叉積表示,其中一條邊已知。向量AB叉乘向量AC=(B.x-A.x)*C.y-(B.y-A.y)*C.x-A.y*(B.x-A.x)+A.x*(B.y-A.y)(這是負的,使其最小)前兩項和C有關,後兩項都已知,重新對邊賦權為(B.x-A.x)*e[i].b-(B.y-A.y)*e[i].a,跑mst,即為C點。

最壞復雜度O(nmlogm)。

如果是三元,那麽就相當於在平面下找最遠點,使得中間體積最大。分割的時候分成三個部分。

bzoj2395 [Balkan 2011]Timeismoney