hdu 5820 可持久化线段树



链接:戳这里


Lights

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)

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
 

题意:

在一个大小为50000*50000的矩形中,有n个路灯。(n<=500000)

询问是否每一对路灯之间存在一条道路,使得长度为|x1 – x2| + |y1 – y2|且每个拐弯点都是路灯。


思路:


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<list>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef long double ld;
#define INF (1ll<<60)-1
#define Max 8000000
using namespace std;
int n;
struct point{
    int x,y;
    point (int x=0,int y=0):x(x),y(y){}
    bool operator < (const point &a)const{
        if(x==a.x) return y<a.y;
        return x<a.x;
    }
}s[1000100];
bool operator == (const point &a,const point &b){
    if(a.x==b.x && a.y==b.y) return true;
    return false;
}
struct node{
    int l,r,sum;
}tr[Max];
int tot;
void build(int &root,int l,int r){
    root=++tot;
    tr[root].l=l;
    tr[root].r=r;
    tr[root].sum=0;
    if(l==r) return ;
    int mid=(l+r)/2;
    build(tr[root].l,l,mid);
    build(tr[root].r,mid+1,r);
    tr[root].sum=tr[tr[root].l].sum+tr[tr[root].r].sum;
}
void update(int &root,int l,int r,int last,int x,int v){
    root=++tot;
    if(l==r){
        tr[root].sum=tr[last].sum+v;
        return ;
    }
    tr[root].l=tr[last].l;
    tr[root].r=tr[last].r;
    int mid=(l+r)/2;
    if(x<=mid) update(tr[root].l,l,mid,tr[last].l,x,v);
    if(x>mid) update(tr[root].r,mid+1,r,tr[last].r,x,v);
    tr[root].sum=tr[tr[root].l].sum+tr[tr[root].r].sum;
}
int query(int root,int l,int r,int x,int y){
    if(x<=l && y>=r){
        return tr[root].sum;
    }
    int mid=(l+r)/2;
    if(y<=mid) return query(tr[root].l,l,mid,x,y);
    else if(x>mid) return query(tr[root].r,mid+1,r,x,y);
    else return query(tr[root].l,l,mid,x,mid)+query(tr[root].r,mid+1,r,mid+1,y);
}
int root[Max],flag=0;
int mx[50100],my[50100];/// 当前点正左方最近的x 正下方最近的y
void gao(){
    tot=0;
    mst(mx,0);
    mst(my,0);
    build(root[0],1,50000);
    int last=root[0];
    for(int i=1;i<=n;i++){
        int x1=s[i].x , y1=s[i].y;
        int x2=s[my[y1]].x , y2=s[mx[x1]].y;
        update(root[x1],1,50000,last,y1,1);
        int num1=query(root[x1],1,50000,y2+1,y1);
        int num2=query(root[x2],1,50000,y2+1,y1);
        if(num1!=num2+1) {
            flag=1;
            return ;
        }
        mx[s[i].x]=i; my[s[i].y]=i; last=root[x1];
    }
}
int main(){
    while(scanf("%d",&n)!=EOF){
        if(n==0) break;
        for(int i=1;i<=n;i++) scanf("%d%d",&s[i].x,&s[i].y);
        sort(s+1,s+n+1);
        int cnt=0;
        for(int i=1;i<=n;i++){
            if(s[i]==s[i+1]) continue;
            s[++cnt]=s[i];
        }
        n=cnt;
        flag=0;
        gao();
        for(int i=1;i<=n;i++) s[i].x=50001-s[i].x;
        sort(s+1,s+n+1);
        gao();
        if(flag) printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}
/*
1 1 0 0
1 3 0 1
3 3 1 0
49998 3 0 0
50000 1 0 0
50000 3 49998 1

3
1 1
1 3
3 3
*/






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值