题目:
128. Snake time limit per test: 0.25 sec. There are N points given by their coordinates on a plane. All coordinates (xi,yi) are integers in a range from -10000 up to 10000 inclusive . It is necessary to construct a broken line satisfying the following conditions: Input First line contains the number N (4 <= N <= 10000) - amount of points. Each of the following N lines contains coordinates of points separated by space xi and yi (1 <= i <= N). Points are given in random order. Output First line should contain the length of the broken line L or 0 if there is no solution. Sample Input Sample Output 4 0 0 0 3 3 3 3 0 Sample Output 12 | ||||||
|
题解:
1.题目要求每条线段必须与x轴或y轴平行,所以每横行、竖行上必须有2的倍数个点
2.线段的构造是唯一的,画个图就知道了
3.可以先构造出图,再判断出线段是否相交
4.将与y轴平行的线段和与x轴平行的线段端点构造成线段树,从左到右依次扫描,遇到与x轴平行的线段的左端点,则插入它的横坐标,遇到右端点,则删除它的横坐标,遇到与y轴平行的线段,则判断在该线段范围(不算端点)内是否有点,如果有点,则相交,图形不合法
5.如遇到横坐标相同,则先处理与x轴平行的线段的右端点,再处理与y轴平行的线段,最后处理与x轴平行的线段的左端点
代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct point
{
int x, y, id;
} p[10001];
struct edge
{
int x1, x2, y1, y2;
} line[10001];
struct event
{
int id, x, type;
} eve[30001];
struct type_tree
{
int a, b, t, l, r;
} tree[100001];
int n, num, connect[10001][2], ans, cnt, maxy = -1, miny = 99999, treenum;
char vis[10001];
void imp()
{
printf("0\n");
exit(0);
}
void init()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
scanf("%d%d", &p[i].x, &p[i].y);
p[i].id = i;
maxy = p[i].y > maxy ? p[i].y : maxy;
miny = p[i].y < miny ? p[i].y : miny;
}
if(n & 1) imp();
}
int cmp1(const void *a, const void *b)
{
struct point *c = (point *) a;
struct point *d = (point *) b;
if(c->y != d->y) return c->y - d->y;
return c->x - d->x;
}
int cmp2(const void *a, const void *b)
{
struct point *c = (point *) a;
struct point *d = (point *) b;
if(c->x != d->x) return c->x - d->x;
return c->y - d->y;
}
int cmp3(const void *c, const void *d)
{
struct event *a = (event*) c;
struct event *b = (event*) d;
if(a->x != b->x) return a->x - b->x;
return a->type - b->type;
}
void createpic()
{
qsort(p + 1, n, sizeof(point), cmp1);
for(int i = 1; i <= n; i += 2)
{
if(p[i].y != p[i + 1].y) imp();
line[++num].x1 = p[i].x;
line[num].x2 = p[i + 1].x;
line[num].y1 = line[num].y2 = p[i].y;
connect[p[i].id][0] = p[i + 1].id;
connect[p[i + 1].id][0] = p[i].id;
ans += p[i + 1].x - p[i].x;
eve[++cnt].type = 0;
eve[cnt].x = p[i + 1].x;
eve[cnt].id = num;
eve[++cnt].type = 2;
eve[cnt].x = p[i].x;
eve[cnt].id = num;
}
qsort(p + 1, n, sizeof(point), cmp2);
for(int i = 1; i <= n; i += 2)
{
if(p[i].x != p[i + 1].x) imp();
line[++num].y1 = p[i].y;
line[num].y2 = p[i + 1].y;
line[num].x1 = line[num].x2 = p[i].x;
connect[p[i].id][1] = p[i + 1].id;
connect[p[i + 1].id][1] = p[i].id;
ans += p[i + 1].y - p[i].y;
eve[++cnt].type = 1;
eve[cnt].x = p[i].x;
eve[cnt].id = num;
}
}
void dfs(int now)
{
vis[now] = true;
if(!vis[connect[now][0]]) dfs(connect[now][0]);
if(!vis[connect[now][1]]) dfs(connect[now][1]);
}
void check_link()
{
dfs(1);
for(int i = 1; i <= n; ++i)
if(!vis[i])
imp();
}
int settree(int a, int b)
{
int now = ++treenum;
tree[now].a = a;
tree[now].b = b;
if((a + b >> 1) > a)
{
tree[now].l = settree(a, a + b >> 1);
tree[now].r = settree(a + b >> 1, b);
}
return now;
}
void ins(int y, int id)
{
int a = tree[id].a, b = tree[id].b;
if(b - a <= 1) ++tree[id].t;
else
{
if(y <= a + b >> 1) ins(y, tree[id].l);
else ins(y, tree[id].r);
tree[id].t = tree[tree[id].l].t + tree[tree[id].r].t;
}
}
void del(int y, int id)
{
int a = tree[id].a, b = tree[id].b;
if(b - a <= 1) --tree[id].t;
else
{
if(y <= a + b >> 1) del(y, tree[id].l);
else del(y, tree[id].r);
tree[id].t = tree[tree[id].l].t + tree[tree[id].r].t;
}
}
int find(int y1, int y2, int id)
{
int a = tree[id].a, b = tree[id].b;
if(y1 <= a && b <= y2) return tree[id].t;
if(b - a <= 1) return 0;
int ans = 0;
if(y1 <= (a + b >> 1)) ans |= find(y1, y2, tree[id].l);
if(y2 > (a + b >> 1)) ans |= find(y1, y2, tree[id].r);
return ans;
}
void check_cross()
{
qsort(eve + 1, cnt, sizeof(event), cmp3);
settree(miny, maxy);
for(int i = 1; i <= cnt; ++i)
{
int id = eve[i].id;
if(!eve[i].type) del(line[id].y1, 1);
else if(eve[i].type == 2) ins(line[id].y1, 1);
else if(find(line[id].y1, line[id].y2, 1)) imp();
}
}
int main()
{
init();
createpic();
check_link();
check_cross();
printf("%d\n", ans);
return 0;
}
//ps:很奇怪,把 /2 改成 >> 1就过了。。。
//代码借鉴了网上大爷的。。。