您的位置:首页 > 其它

sgu 128

2015-11-26 22:03 253 查看

题意:

在平面上有N个点,现在要求一些线段,使其满足以下要求:

a. 这些线段必须闭合

b. 线段的端点只能是这N个点

c. 交于一点的两条线段成90度角

d. 线段都必须平行于坐标轴

e. 所有线段除在这N个点外不自交

f. 所有线段的长度之和必须最短

如果存在这样的线段,则输出最小长度,否则输出0。

解:a.并查集判断是否是一个闭合图形而不是两个闭合图形

b.c. d. 可知每一行每一列的坐标上点的数量必须为偶数,若为奇数则肯定会有一个多余的点无法连入图中

f.可推断出若要满足以上条件一定只有一个图存在,所以不用判断是否为最小周长

e.用线段树判断:单点修改,区间查询;

代码如下:

#include<iostream>

#include<algorithm>

#include<vector>

#include<stdio.h>

#define lson (id*2)

#define rson (id*2+1)

using namespace std;

struct edge{

int x;int y;int val;int id;

}tree[80010],p[50005];

vector<int>linx[50010];

vector<int>liny[50010];

int fa[10010];

int find(int a)

{

if (fa[a]==a)

return a;

return fa[a]=find(fa[a]);

}

int unio(int a,int b)

{

fa[find(a)]=find(b);

return 0;

}

int cmp1(edge a,edge b)

{

if (a.x!=b.x)

return a.x<b.x;

else

return a.y<b.y;

}

int cmp2(edge a,edge b)

{

if (a.y!=b.y)

return a.y<b.y;

else

return a.x<b.x;

}

int ans=0;

//开始建树

void push_up(int id)

{

tree[id].val=tree[lson].val+tree[rson].val;

return ;

}

void build_tree(int id,int l,int r)

{

if (l>=r)

{

tree[id].val=0;

return ;

}

int mid=(l+r)/2;

build_tree(lson,l,mid);

build_tree(rson,mid+1,r);

push_up(id);

return ;

}

void add_tree(int id,int l,int r,int x)

{

if (l==r&&r==x)

{

tree[id].val+=1;

tree[id].val%=2;

return ;

}

int mid=(l+r)/2;

if (mid>=x)

add_tree(lson,l,mid,x);

else

add_tree(rson,mid+1,r,x);

push_up(id);

return ;

}

void query_tree(int id,int l,int r,int L,int R)

{

if (L>R) return;

if (L<=l&&R>=r)

{

ans+=tree[id].val;

return ;

}

int mid=(l+r)/2;

if (mid>=L)

query_tree(lson,l,mid,L,R);

if (mid+1<=R)

query_tree(rson,mid+1,r,L,R);

return ;

}//建树完毕

int n,mx=-10004,my=-10004;

long long C=0;

void solve_before()

{

sort(p+1,p+1+n,cmp1);

for (int i=1;i<=n;i++)

linx[p[i].x].push_back(p[i].y);

sort(p+1,p+1+n,cmp2);

for (int i=1;i<=n;i++)

liny[p[i].y].push_back(p[i].x);

sort(p+1,p+1+n,cmp1);

}

int main()

{

build_tree(1,1,20001);

scanf("%d",&n);

for (int i=1;i<=n;i++)

fa[i]=i;

for (int i=1;i<=n;i++)

{

scanf("%d%d",&p[i].x,&p[i].y);

p[i].x+=10001;

p[i].y+=10001;

p[i].id=i;

mx=max(mx,p[i].x);

my=max(my,p[i].y);

}

solve_before();

for (int i=0;i<=max(mx,my);i++)

{

if (linx[i].size()%2!=0||liny[i].size()%2!=0)

{

cout<<"0"<<endl;

return 0;

}

}

for (int i=1;i<=n;i+=2)

{

ans=0;

C+=p[i+1].y-p[i].y;

unio(p[i].id,p[i+1].id);

add_tree(1,1,20001,p[i].y);

add_tree(1,1,20001,p[i+1].y);

query_tree(1,1,20001,p[i].y+1,p[i+1].y-1);

if (ans>0)

{

cout<<"0"<<endl;

return 0;

}

}

sort(p+1,p+1+n,cmp2);

for (int i=1;i<=n;i+=2)

{

unio(p[i+1].id,p[i].id);

C+=p[i+1].x-p[i].x;

}

for (int i=1;i<n;i++)

{

if (find(i)!=find(i+1))

{

cout<<"0"<<endl;

return 0;

}

}

cout<<C<<endl;

return 0;

}

更具体题解参考 : http://blog.sina.com.cn/s/blog_51cea4040100gf9l.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: