Problem Description
Today is April 1st, 2100. Now Guangzhou is a very very big city. Since the number of traffic accidents increased last month, the mayor asked Mr. Chopsticks to investigate the traffic condition of the city.
After studying the map of Guangzhou for a while, Mr. Chopsticks has some ideas. Guangzhou can be considered as a rectangular grid with 50000 horizontal streets running west-east (labeled with y-coordinates from 1 to 50000) and 50000 vertical streets running north-south (labeled with x-coordinates from 1 to 50000). All streets are two-way streets. A crossroad is an intersection of a horizontal street and a vertical street, so a crossroad can be represented by (x, y), where x and y are coordinates of the horizontal street and vertical street respectively. Since there are too many streets, traffic lights are not placed at all crossroads. Given two crossroads (x1, y1) and (x2, y2), a path between these two crossroads is said to be good if the length of the path is |x1 – x2| + |y1 – y2| and there exist a traffic light at each turn of this path. Of course, a path must be along the streets, and a turn can only be at a crossroad.
Now given locations of all traffic lights in Guangzhou, Mr. Chopsticks wants to check whether there exists at least one good path between every pair of traffic lights. As Mr. Chopsticks is busy in preparing ACMICPC 2100, he asks you for help.
After studying the map of Guangzhou for a while, Mr. Chopsticks has some ideas. Guangzhou can be considered as a rectangular grid with 50000 horizontal streets running west-east (labeled with y-coordinates from 1 to 50000) and 50000 vertical streets running north-south (labeled with x-coordinates from 1 to 50000). All streets are two-way streets. A crossroad is an intersection of a horizontal street and a vertical street, so a crossroad can be represented by (x, y), where x and y are coordinates of the horizontal street and vertical street respectively. Since there are too many streets, traffic lights are not placed at all crossroads. Given two crossroads (x1, y1) and (x2, y2), a path between these two crossroads is said to be good if the length of the path is |x1 – x2| + |y1 – y2| and there exist a traffic light at each turn of this path. Of course, a path must be along the streets, and a turn can only be at a crossroad.
Now given locations of all traffic lights in Guangzhou, Mr. Chopsticks wants to check whether there exists at least one good path between every pair of traffic lights. As Mr. Chopsticks is busy in preparing ACMICPC 2100, he asks you for help.
Input
The input contains multiple test cases. Each case begins with an integer N (1 <= N <= 500000), indicating the number of traffic lights. The following N lines each contain two integers x and y (1 <= x, y <= 50000), indicating a location of a traffic light. There may be multiple traffic lights at the same location.
N = 0 indicates the end of the input.
N = 0 indicates the end of the input.
Output
For each case, output “YES” if there exists at least one good path between every pair of traffic lights; otherwise output “NO”.
Sample Input
2 1 1 3 3 3 1 1 1 3 3 3 0
Sample Output
NO YES
我们考虑对于(x,y),他正上方最近的点(x,y'),他左方最近的点(x'',y)
这三个点围成一个矩形范围,显然如果其中有其他点则不可行
因此我们对点排序,一排排扫描过去
对每对(x,y)和(x,y'),统计x''到x之间,y到y'的点的数量
正下方的点同理
如果没有某个方向的点,则那个点默认在边界上即可
可以用可持久化线段树来维护
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct point
{
int x,y;
}a[500001];
struct tree
{
int ll,rr;
int x;
}tr[7500001];
int root[100001];
int tot;
inline void build(int l,int r)
{
int p=tot;
if(l!=r)
{
int mid=(l+r)/2;
tot++;
tr[p].ll=tot;
build(l,mid);
tot++;
tr[p].rr=tot;
build(mid+1,r);
}
}
inline int inc(int p,int l,int r,int x,int lt,int rt)
{
if(p==0)
return 0;
if(l==lt&&rt==r)
{
tot++;
tr[tot].x=tr[p].x+x;
return tot;
}
else
{
int mid=(lt+rt)/2;
tot++;
int pp=tot;
if(l<=mid)
tr[pp].ll=inc(tr[p].ll,l,r,x,lt,mid);
else
tr[pp].ll=tr[p].ll;
if(r>mid)
tr[pp].rr=inc(tr[p].rr,l,r,x,mid+1,rt);
else
tr[pp].rr=tr[p].rr;
tr[pp].x=tr[tr[pp].ll].x+tr[tr[pp].rr].x;
return pp;
}
}
inline int ask(int p,int l,int r,int lt,int rt)
{
if(l>r)
return 0;
if(l<=lt&&rt<=r)
return tr[p].x;
else
{
int mid=(lt+rt)/2;
int ans=0;
if(l<=mid)
ans+=ask(tr[p].ll,l,r,lt,mid);
if(r>mid)
ans+=ask(tr[p].rr,l,r,mid+1,rt);
return ans;
}
}
int xx;
inline bool cmp(point x,point y)
{
return x.x<y.x||x.x==y.x&&x.y<y.y;
}
int v[100001];
int main()
{
int n;
scanf("%d",&n);
while(n!=0)
{
tot=1;
memset(v,0,sizeof(v));
memset(tr,0,sizeof(tr));
memset(root,0,sizeof(root));
int i,j;
for(i=1;i<=n;i++)
scanf("%d%d",&a[i].x,&a[i].y);
sort(a+1,a+1+n,cmp);
build(1,50000);
root[0]=1;
int rt=1;
bool flag=true;
int d=1,dx;
for(i=1;i<=n+1;i++)
{
if(a[i].x==a[i-1].x)
{
int as1=ask(rt,a[i-1].y+1,a[i].y-1,1,50000);
int as2=ask(root[v[a[i-1].y]],a[i-1].y+1,a[i].y-1,1,50000);
if(as1!=as2)
{
flag=false;
break;
}
}
else
{
dx=i-1;
for(j=dx;j>=d;j--)
{
if(j!=dx)
{
int as1=ask(rt,a[j].y+1,a[j+1].y-1,1,50000);
int as2=ask(root[v[a[j+1].y]],a[j].y+1,a[j+1].y-1,1,50000);
if(as1!=as2)
{
flag=false;
break;
}
}
else
{
int as1=ask(rt,a[j].y+1,50000,1,50000);
int as2=ask(root[v[a[j].y]],a[j].y+1,50000,1,50000);
if(as1!=as2)
{
flag=false;
break;
}
}
root[a[j].x]=tot+1;
inc(rt,a[j].y,a[j].y,1,1,50000);
rt=root[a[j].x];
}
for(j=dx;j>=d;j--)
v[a[j].y]=a[j].x;
d=i;
if(i>n)
break;
int as1=ask(rt,1,a[i].y-1,1,50000);
int as2=ask(root[v[a[i].y]],1,a[i].y-1,1,50000);
if(as1!=as2)
{
flag=false;
break;
}
}
}
if(flag)
printf("YES\n");
else
printf("NO\n");
scanf("%d",&n);
}
return 0;
}