正题
题目链接:https://jzoj.net/senior/#contest/show/3002/1
题目大意
nnn个点mmm条边,每条边有(u,v)(u,v)(u,v)两个权值。
qqq个询问,每次询问一个(k1,k2)(k1,k2)(k1,k2),将所有边的权值变为u∗k1+v∗k2u*k1+v*k2u∗k1+v∗k2后求最小生成树。
解题思路
首先u∗k1+v∗k2⇒(u+v∗k2k1)∗k1u*k1+v*k2\Rightarrow (u+v*\frac{k2}{k1})*k1u∗k1+v∗k2⇒(u+v∗k1k2)∗k1,所以决策可以线性表示出来。
我们考虑维护一个坐标系(x,y)(x,y)(x,y)表示uuu值和为xxx的生成树中yyy值和最小是多少。
显然xxx增大时yyy在减小,所以这是一个下突壳。
考虑维护这一个突壳,首先是两个端点l:(k1=0,k2=1)l:(k1=0,k2=1)l:(k1=0,k2=1)时和r:(k1=1,k2=0)r:(k1=1,k2=0)r:(k1=1,k2=0)各做一次最小生成树,此时我们考虑找到一个在线段(l,r)(l,r)(l,r)的左下角最远的点midmidmid。
通过差积各种证明后我们发现有mid(k1=∣yl−yr∣,k2=∣xl−xr∣)mid(k1=|y_l-y_r|,k2=|x_l-x_r|)mid(k1=∣yl−yr∣,k2=∣xl−xr∣),然后分治下去处理(l,mid)(l,mid)(l,mid)和(r,mid)(r,mid)(r,mid)。
当midmidmid在线段(l,r)(l,r)(l,r)上时,证明左下角已经没有更优的点,所以可以返回了。
最后在突壳上三分答案就好了。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int M=25100,N=40;
struct node{int x,y;double u,v;
}a[M];
struct knode{double k1,k2,x,y;
}k[M*4],head,tail;
int n,m,q,fa[N],tot;
double k1,k2;
int find(int x)
{return fa[x]==x?x:(fa[x]=find(fa[x]));}
bool cmp(node x,node y)
{return x.u*k1+x.v*k2<y.u*k1+y.v*k2;}
void Get_Tree(knode &k){k1=k.k1;k2=k.k2;k.x=k.y=0;sort(a+1,a+1+m,cmp);for(int i=1;i<=n;i++)fa[i]=i;int z=n;for(int i=1;i<=m;i++){int fx=find(a[i].x),fy=find(a[i].y);if(fx!=fy){if(fx>fy) swap(fx,fy);fa[fy]=fx;z--;k.x+=a[i].u;k.y+=a[i].v;}}return;
}
void Solve(knode l,knode r){knode mid;mid.k1=fabs(r.y-l.y);mid.k2=fabs(r.x-l.x);Get_Tree(mid);if(l.y==mid.y||l.y==r.y||(l.x-r.x)/(l.y-r.y)==(l.x-mid.x)/(l.y-mid.y))return;Solve(l,mid);k[++tot]=mid;Solve(mid,r);
}
int main()
{scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=m;i++)scanf("%d%d%lf%lf",&a[i].x,&a[i].y,&a[i].u,&a[i].v);head.k1=1;tail.k2=1;Get_Tree(head);Get_Tree(tail);k[tot=1]=head;Solve(head,tail);k[++tot]=tail;while(q--){scanf("%lf%lf",&k1,&k2);int l=1,r=tot;double ans=1e18;while(l<r){if(r-l<=2)break;int mid1=l+(r-l+1)/3,mid2=l+(r-l+1)/3*2;if(k[mid1].x*k1+k[mid1].y*k2<k[mid2].x*k1+k[mid2].y*k2) r=mid2;else l=mid1;}for(int i=l;i<=r;i++)ans=min(k[i].x*k1+k[i].y*k2,ans);printf("%.3lf\n",ans);}
}