kattis Grid MST (最小曼哈顿生成树)

来源:互联网 发布:php记录访客信息 编辑:程序博客网 时间:2024/05/17 09:18

Grid MST

This is a very simple problem. You are given NN points. Some points may be repeated. The weight (distance) between two points is given by the Manhattan distance between the two points. Find the weight of a Minimum Spanning Tree that spans these NN points.

Input

The input consists of:

  • One line with one integer NN (1N1000001≤N≤100000), the number of points,

  • NN lines each with two integers xx and yy (0x,y<10000≤x,y<1000), the coordinates of each point.

Output

Output one line with a single integer: The weight of a Minimum Spanning Tree that spans these NN points.

Sample Input 1Sample Output 1
40 00 11 01 1
3
Sample Input 2Sample Output 2
50 010 010 011 112 2
14
解题思路:最小曼哈顿生成树裸题,最小曼哈顿生成树难点在于建图,其实不必每个点都要与其他n - 1个点相连,每个点只需要与周围最近的八个点相连就行,这八个点分别对应于以这个点为中心的八个区域,然后我们可以通过坐标变换,变成只处理右上方45度的区域,然后 处理四个区域,也就是变换四次就行(因为要求的是最小生成树,a ->b, b->a相同的效果),然后具体处理是用树状数组或者线段树按y - x离散,维护一个x + y的最小值就行。
线段树:
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 100000 + 10;LL inf = 1e18;int n;int tot;int father[maxn];struct point{    int x, y, id;    bool operator <(const point &res) const    {        if(x == res.x) return y < res.y;        else return x < res.x;    }} Point[maxn<<4];struct edge{    int u, v;    LL w;    bool operator <(const edge &res) const    {        return w < res.w;    }} Edge[maxn<<10];struct node{    int l, r, id;    LL Min;} Node[maxn<<6];void add(int u, int v, LL w){    Edge[++tot].u = u;    Edge[tot].v = v;    Edge[tot].w = w;}void Pushup(int i){    int lson = i<<1;    int rson = lson|1;    if(Node[lson].Min <= Node[rson].Min)    {        Node[i].Min = Node[lson].Min;        Node[i].id = Node[lson].id;    }    else    {        Node[i].Min = Node[rson].Min;        Node[i].id = Node[rson].id;    }}void build(int i, int l, int r){    Node[i].l = l;    Node[i].r = r;    Node[i].Min = inf;    Node[i].id = -1;    if(l == r) return;    int f = i;    int mid = (l + r)>>1;    i <<= 1;    build(i, l, mid);    build(i|1, mid + 1, r);    //Pushup(f);}void update(int i, int loc, LL value, int id){    if(Node[i].l == Node[i].r)    {        if(value >= Node[i].Min) return;        Node[i].Min = value;        Node[i].id = id;        return;    }    int f = i;    i <<= 1;    if(loc <= Node[i].r) update(i, loc, value, id);    else update(i|1, loc, value, id);    Pushup(f);}pair<LL, int> query(int i, int l, int r){    if(Node[i].l == l && Node[i].r == r)    {        return make_pair(Node[i].Min, Node[i].id);    }    i <<= 1;    if(r <= Node[i].r) return query(i, l, r);    else if(l >= Node[i|1].l) return query(i|1, l, r);    else    {        pair<LL, int> pp1 = query(i, l, Node[i].r);        pair<LL, int> pp2 = query(i|1, Node[i|1].l, r);        if(pp1.first <= pp2.first) return pp1;        else return pp2;    }}void Tran(int type){    if(type == 1)    {        sort(Point + 1, Point + n + 1);        return;    }    else if(type == 2 || type == 4)    {        for(int i = 1; i <= n; i++)        {            swap(Point[i].x, Point[i].y);        }        sort(Point + 1, Point + n + 1);        return;    }    else if(type == 3)    {        for(int i = 1; i <= n; i++)        {            Point[i].x = -Point[i].x;        }        sort(Point + 1, Point + n + 1);        return;    }}void getGraph(){    for(int i = 1; i <= 4; i++)    {        Tran(i);        build(1, 0, 4000);        for(int j = n; j >= 1; j--)        {            int loc = Point[j].y - Point[j].x;            loc += 2000;            pair<LL, int> pp = query(1, loc, 4000);            if(pp.first < inf)            {                int id = pp.second;                add(Point[j].id, id, pp.first - LL(Point[j].x + Point[j].y));            }            update(1, loc, (LL)(Point[j].x + Point[j].y), Point[j].id);        }    }}void init(){    tot = 0;    for(int i = 1; i <= n; i++) father[i] = i;}int Find(int x){    if(father[x] == x) return x;    else return father[x] = Find(father[x]);}LL kruscal(){    LL ans = 0;    int judge = 0;    sort(Edge + 1, Edge + tot + 1);    for(int i = 1; i <= tot; i++)    {        int u = Edge[i].v;        int v = Edge[i].u;        LL w = Edge[i].w;        int f1 = Find(u);        int f2 = Find(v);        if(f1 != f2)        {            judge++;            ans += w;            father[f1] = f2;        }        if(judge == n - 1) break;    }    return ans;}int main(){    freopen("C:\\Users\\creator\\Desktop\\in1.txt","r",stdin) ;    scanf("%d", &n);    for(int i = 1; i <= n; i++)    {        scanf("%d%d", &Point[i].x, &Point[i].y);        Point[i].id = i;    }    init();    getGraph();    printf("%lld\n", kruscal());    return 0;}
树状数组:
#include <bits/stdc++.h>using namespace std;typedef long long LL;inline bool scan_d(int &num){        char in;bool IsN=false;        in=getchar();        if(in==EOF) return false;        while(in!='-'&&(in<'0'||in>'9')) in=getchar();        if(in=='-'){ IsN=true;num=0;}        else num=in-'0';        while(in=getchar(),in>='0'&&in<='9'){                num*=10,num+=in-'0';        }        if(IsN) num=-num;        return true;}const int maxn = 100000 + 10;LL inf = 1e18;int n;int tot;int father[maxn];struct point{    int x, y, id;    bool operator <(const point &res) const    {        if(x == res.x) return y < res.y;        else return x < res.x;    }} Point[maxn<<4];struct edge{    int u, v;    LL w;    bool operator <(const edge &res) const    {        return w < res.w;    }} Edge[maxn<<10];struct BITnode{    LL w;    int id;}Tree[maxn<<1];LL H[maxn<<1];int num;int lowbit(int x){    return x&(-x);}int Hash(LL key){    return lower_bound(H, H + num, key) - H + 1;}void add_edge(int u, int v, LL w){    Edge[++tot].u = u;    Edge[tot].v = v;    Edge[tot].w = w;}void Tran(int type){    if(type == 1)    {        sort(Point + 1, Point + n + 1);        return;    }    else if(type == 2 || type == 4)    {        for(int i = 1; i <= n; i++)        {            swap(Point[i].x, Point[i].y);        }        sort(Point + 1, Point + n + 1);        return;    }    else if(type == 3)    {        for(int i = 1; i <= n; i++)        {            Point[i].x = -Point[i].x;        }        sort(Point + 1, Point + n + 1);        return;    }}void add(int loc, LL v, int id){    for(int i = loc; i >= 1; i -= lowbit(i))    {        if(Tree[i].w > v)        {            Tree[i].w = v;            Tree[i].id = id;        }    }}int query(int loc){    LL Min = inf;    int id = -1;    for(int i = loc; i <= num; i += lowbit(i))    {        if(Tree[i].w < Min)        {            Min = Tree[i].w;            id = i;        }    }    return id;}void getGraph(){    for(int i = 1; i <= 4; i++)    {        Tran(i);        num = 0;        for(int j = n; j >= 1; j--)        {            Tree[j].id = -1;            Tree[j].w = inf;            LL key = LL(Point[j].y - Point[j].x);            H[num++] = key;        }        sort(H, H + num);        num = unique(H, H + num) - H;        for(int j = n; j >= 1; j--)        {            LL key = LL(Point[j].y - Point[j].x);            LL v = LL(Point[j].x + Point[j].y);            int loc = Hash(key);            int id = query(loc);            if(id != -1)            {                add_edge(Point[j].id, Tree[id].id, Tree[id].w - v);            }            add(loc, v, Point[j].id);        }    }}void init(){    tot = 0;    for(int i = 1; i <= n; i++) father[i] = i;}int Find(int x){    if(father[x] == x) return x;    else return father[x] = Find(father[x]);}LL kruscal(){    LL ans = 0;    int judge = 0;    sort(Edge + 1, Edge + tot + 1);    for(int i = 1; i <= tot; i++)    {        int u = Edge[i].v;        int v = Edge[i].u;        LL w = Edge[i].w;        int f1 = Find(u);        int f2 = Find(v);        if(f1 != f2)        {            judge++;            ans += w;            father[f1] = f2;        }        if(judge == n - 1) break;    }    return ans;}int main(){   // freopen("C:\\Users\\creator\\Desktop\\in1.txt","r",stdin) ;    scanf("%d", &n);    for(int i = 1; i <= n; i++)    {        //scanf("%d%d", &Point[i].x, &Point[i].y);        scan_d(Point[i].x);        scan_d(Point[i].y);        Point[i].id = i;    }    init();    getGraph();    printf("%lld\n", kruscal());    return 0;}



原创粉丝点击