2016多校训练Contest7: 1012 Lights hdu5820

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.
 

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.
 

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值