bzoj4061 [Cerc2012]Farm and factory(贪心+Dijkstra+切比雪夫距离)

记新首都为x点,我们对于每一个原来的点u都需要满足
dis[u][x]+dis[x][1]>=dis0[u][1],dis[u][x]+dis[x][2]>=dis0[u][2] d i s [ u ] [ x ] + d i s [ x ] [ 1 ] >= d i s 0 [ u ] [ 1 ] , d i s [ u ] [ x ] + d i s [ x ] [ 2 ] >= d i s 0 [ u ] [ 2 ]
其中 dis[i][j] d i s [ i ] [ j ] 表示加入新点x之后的最短路, dis0 d i s 0 表示原图的最短路。
因此我们有 dis[u][x]>=max{dis0[u][1]dis[x][1],dis0[u][2]dis[x][2]} d i s [ u ] [ x ] >= m a x { d i s 0 [ u ] [ 1 ] − d i s [ x ] [ 1 ] , d i s 0 [ u ] [ 2 ] − d i s [ x ] [ 2 ] }
我们把 (dis0[u][1],dis0[u][2]) ( d i s 0 [ u ] [ 1 ] , d i s 0 [ u ] [ 2 ] ) 看做一个点,那么就是求这n个点到一个点的切比雪夫距离之和最小。
我们把坐标系旋转45度,变成曼哈顿距离,然后就可以贪心的每一维取中位数达到最小了。
复杂度 O((n+m)logn) O ( ( n + m ) l o g n )

#include 
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
#define pi pair
inline char gc(){
    static char buf[1<<16],*S,*T;   
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,m,h[N],num=0;
ll di[2][N],a[N];bool vis[N];
struct edge{
    int to,next,val;
}data[N*6];
inline void Dij(int s,ll *dis){
    priority_queuevector,greater >q;memset(dis,inf,sizeof(dis[0])*(n+1));
    q.push(make_pair(0,s));dis[s]=0;memset(vis,0,sizeof(vis[0])*(n+1));
    while(!q.empty()){
        int x=q.top().second;q.pop();if(vis[x]) continue;vis[x]=1;
        for(int i=h[x];i;i=data[i].next){
            int y=data[i].to;
            if(dis[x]+data[i].valint main(){
//  freopen("a.in","r",stdin);
    int tst=read();
    while(tst--){
        n=read();m=read();ll ans=0;memset(h,0,sizeof(h[0])*(n+1));num=0;
        while(m--){
            int x=read(),y=read(),val=read();
            data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;
            data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].val=val;
        }Dij(1,di[0]);Dij(2,di[1]);
        for(int i=1;i<=n;++i) a[i]=di[0][i]+di[1][i];sort(a+1,a+n+1);
        for(int i=1;i<=n/2;++i) ans+=a[n-i+1]-a[i];
        for(int i=1;i<=n;++i) a[i]=di[0][i]-di[1][i];sort(a+1,a+n+1);
        for(int i=1;i<=n/2;++i) ans+=a[n-i+1]-a[i];
        printf("%.8lf\n",ans*0.5/n);
    }return 0;
}

你可能感兴趣的:(bzoj,贪心,最短路)