Cod sursa(job #1710149)

Utilizator AlexandruValeanuAlexandru Valeanu AlexandruValeanu Data 28 mai 2016 16:21:52
Problema Metrou4 Scor 0
Compilator cpp Status done
Runda Arhiva ICPC Marime 4.15 kb
#include <bits/stdc++.h>

using namespace std;

class DSU
{
public:

    DSU( const int _N )
    {
        N = _N;

        Father = vector<int>( N + 1, 0 );
        Rank = vector<int> ( N + 1, 0 );

        initialise();
    }

    void initialise()
    {
        for ( int i = 1; i <= N; ++i )
        {
            Father[i] = i;
            Rank[i] = 1;
        }
    }

    int Find( int node )
    {
        int root = node, auxNode;

        while ( Father[ root ] != root )
            root = Father[ root ];

        while ( root != Father[ node ] )
        {
            auxNode = Father[ node ];
            Father[ node ] = root;
            node = auxNode;
        }

        return root;
    }

    int Check( int x, int y )
    {
        return ( Find( x ) == Find( y ) );
    }

    void Union( int x, int y )
    {
        int fx = Find( x );
        int fy = Find( y );

        if ( fx != fy )
        {
            x = fx; y = fy;

            if ( Rank[x] < Rank[y] )
                Father[x] = y;
            else
                Father[y] = x;

            if ( Rank[x] == Rank[y] )
                Rank[y]++;
        }
    }

private:

    vector <int> Father, Rank;
    int N;
};

const int Nmax = 100000 + 1;
const int INF = 0x3f3f3f3f;

struct Edge
{
    int a, b, c;

    bool operator < ( const Edge &E ) const
    {
        return c < E.c;
    }

} Edges[8 * Nmax];

int neighbor[Nmax];
int distToNeighbor[Nmax];
int ind[Nmax];

int X[Nmax], Y[Nmax];
int N, nrEdges;

bool cmp1( const int a, const int b )
{
    if ( Y[a] != Y[b] )
        return Y[a] < Y[b];
    else
        return X[a] < X[b];
}

bool cmp2( const int a, const int b )
{
    return Y[a] - X[a] < Y[b] - X[b];
}

void solve( int st, int dr )
{
    if ( dr - st <= 1 )
        return;

    int m = ( st + dr ) / 2;

    solve( st, m );
    solve( m, dr );

    int distToNeigh = INF;
    int neigh = -1;

    for ( int i = st, j = m; i < m; ++i )
    {
        while ( j < dr && Y[ ind[j] ] - X[ ind[j] ] <= Y[ ind[i] ] - X[ ind[i] ] )
        {
            if ( distToNeigh > X[ ind[j] ] + Y[ ind[j] ] )
            {
                distToNeigh = X[ ind[j] ] + Y[ ind[j] ];
                neigh = ind[j];
            }

            j++;
        }

        if ( distToNeighbor[ ind[i] ] > distToNeigh )
        {
            distToNeighbor[ ind[i] ] = distToNeigh;
            neighbor[ ind[i] ] = neigh;
        }
    }

    inplace_merge( ind + st, ind + m, ind + dr, cmp2 );
}

int main()
{
    ifstream in("metrou4.in");
    ofstream out("metrou4.out");

    ios_base::sync_with_stdio( false );

    int T;
    in >> T;

    while (T--)
    {
        in >> N;

        nrEdges = 0;

        memset(X, 0, sizeof X);
        memset(Y, 0, sizeof Y);
        memset(distToNeighbor, 0, sizeof distToNeighbor);
        memset(ind, 0, sizeof ind);
        memset(neighbor, 0, sizeof neighbor);

        for ( int i = 0; i < N; ++i )
            in >> X[i] >> Y[i];

        for ( int octant = 0; octant < 8; ++octant )
        {
            memset( distToNeighbor, 0x3f, sizeof( distToNeighbor ) );
            memset( neighbor, -1, sizeof( neighbor ) );

            for ( int i = 0; i < N; ++i )
                ind[i] = i;

            sort( ind, ind + N, cmp1 );

            solve( 0, N );

            for ( int i = 0; i < N; ++i )
                if ( ~neighbor[i] )
                {
                    int c = abs( X[i] - X[ neighbor[i] ] ) + abs( Y[i] - Y[ neighbor[i] ] );
                    Edges[ ++nrEdges ] = Edge{ i + 1, neighbor[i] + 1, c };
                }

            if ( octant & 1 )
            {
                for ( int i = 0; i < N; ++i )
                    X[i] = -X[i];
            }
            else
            {
                for ( int i = 0; i < N; ++i )
                    swap( X[i], Y[i] );
            }
        }

        DSU D( N );

        sort( Edges + 1, Edges + nrEdges + 1 );

        long long sol = 0;

        for ( int i = 1; i <= nrEdges; ++i )
        {
            if ( D.Check( Edges[i].a, Edges[i].b ) == false )
            {
                sol += Edges[i].c;
                D.Union( Edges[i].a, Edges[i].b );
            }
        }

        out << sol << "\n";
    }

    return 0;
}