JZOJ3577. 【CEOI2011】Traffic

7 篇文章 0 订阅
1 篇文章 0 订阅

Description

Gdynia 的中心坐落于Kacza 河中游的一个岛屿上。每天早晨,成千辆小车从河流的西岸的住宅区出发穿过岛屿(使用连接岛西路口的桥梁)到达东岸的工业区(使用连接岛东路口的桥梁)。

这个岛屿酷似一个边平行于坐标轴的矩形。因此,我们视他为一个笛卡尔坐标系上的A*B的矩形,对角的坐标为(0,0) 和(A,B)。

在这个岛屿上,有n 个路口从1 到n 编号。路口i 位于坐标(xi; yi)。如果一个路口坐标类似于(0,y),那么它在岛西。类似的,坐标形于(A,y) 的路口坐落在岛东。路口通过街道连接起来。每一条街道是一条连接两个路口的线段。街道可以是双向或者单向的。没有两条街道有公共点(除了作为线段端点的路口)。岛上没有桥或者地道。其他的道路网络形状是不被认可的。特别的是,街道可以与岛屿的边缘重合,或者存在没有连接街道的路口。

因为交通密度不断增长,所以市长雇佣你去检查现在的道路网络是否足够。他要求你写一个程序,确定从每个岛西的路口出发能到达多少个岛东的路口。

Input

输入的第一行包含四个整数n,m,A和B(1<=n<=300 000; 0<=m<=900 000; 1<=A,B<=10^9)。他们分别表示Gdynia 中心的路口数、街道数和岛屿的尺寸。

在接下来n 行的每一行中有两个整数xi,yi(0<=xi<=A, 0<= yi<= B),描述路口i 的坐标。没有两个路口有相同的坐标。

接下来的m 行描述街道。每条街道用单独的一行表示,每行包含三个整数ci, di, ki(1<= ci, di<=n; ci = di; ki=1或2)。它们的意思是,路口ci 和di 被一条街道连接。如果ki = 1,那么这是一条从ci 到di 的单向道路。否则,这条道路是双向的。每个无序对{ci,di}在输入中最多出现一次。

你可以认为,有至少一个在岛西的路口可能到达岛东的一些路口。

Output

你的程序应该对于每个岛西的路口都输出一行。这一行应该是这个路口能到达的岛东的路口个数。输出的顺序按照岛西路口y 坐标从大到小输出。

Sample Input

输入1:

5 3 1 3

0 0

0 1

0 2

1 0

1 1

1 4 1

1 5 2

3 5 2

输入2:

12 13 7 9

0 1

0 3

2 2

5 2

7 1

7 4

7 6

7 7

3 5

0 5

0 9

3 9

1 3 2

3 2 1

3 4 1

4 5 1

5 6 1

9 3 1

9 4 1

9 7 1

9 12 2

10 9 1

11 12 1

12 8 1

12 10 1

Sample Output

输出1:

2

0

2

输出2:

4

4

0

2

Data Constraint

在总值30points 的数据里,n,m<=6 000。

题解

题目上有一个条件:没有两条街道有公共点(除了作为线段端点的路口)。
通过这个条件就可以知道左边一个点能到达右边的一定是连续的一段区间,
也就是说只要知道能到达最上面和最下面分别是什么,就可以统计出答案了。

首先,从左边向右边进行一次bfs,就右边不可能被到达的点去掉。
然后,建出反图,先按照右边点的升序进行bfs,
每一个点被第一次遍历的时候,就是它能到达的最下面的位置。
同理,再按照降序进行bfs,就可以得到能到达最上面的位置。

code

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h> 
#define ll long long
#define N 1000003
#define db double
#define P putchar
#define G getchar
#define inf 998244353
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

db max(db a,db b){return a>b?a:b;}
db min(db a,db b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

struct node
{
    int x,y;
}a[N*2],b[N],c[N];
int n,m,A,B,x,y,t,f[N],w,ans,m1,m2;
int nxt[N*2],to[N*2],last[N*2],tot;
int l,r,d[N],mi[N],mx[N];
bool bz[N];

bool cmp(node a,node b)
{
    return a.x<b.x || (a.x==b.x && a.y<b.y);
}

void ins(int x,int y)
{
    nxt[++tot]=last[x];
    to[tot]=y;
    last[x]=tot;
}

void bfs(int x)
{
    l=bz[x]=0;
    d[r=1]=x;
    while(l<r)
    {
        x=d[++l];
        for(int i=last[x];i;i=nxt[i])
            if(bz[to[i]])
                bz[to[i]]=0,d[++r]=to[i];
    }
}

void bfs1(int x)
{
    l=bz[x]=0;
    d[r=1]=x;
    while(l<r)
    {
        x=d[++l];
        for(int i=last[x];i;i=nxt[i])
            if(bz[to[i]])bz[to[i]]=0,mi[to[i]]=mi[x],d[++r]=to[i];
    }
}

void bfs2(int x)
{
    l=bz[x]=0;
    d[r=1]=x;
    while(l<r)
    {
        x=d[++l];
        for(int i=last[x];i;i=nxt[i])
            if(bz[to[i]])bz[to[i]]=0,mx[to[i]]=mx[x],d[++r]=to[i];
    }
}

int main()
{
    read(n);read(m);read(A);read(B);
    for(int i=1;i<=n;i++)
    {
        read(x);read(y);f[i]=-123;
        if(x==0)
        {
            b[++m1].x=-y;
            b[m1].y=i;
        }
        if(x==A)f[i]=y;
    }
    for(int i=1;i<=m;i++)
    {
        read(x);read(y);read(t);
        if(t==1)
        {
            w++;
            a[w].x=x;
            a[w].y=y; 
        }
        else
        {
            w++;
            a[w].x=x;
            a[w].y=y; 
            w++;
            a[w].x=y;
            a[w].y=x; 
        }
    }
    sort(a+1,a+1+w,cmp);
    sort(b+1,b+1+m1,cmp);
    for(int i=1;i<=w;i++)
        if(a[i].x!=a[i-1].x || a[i].y!=a[i-1].y)ins(a[i].x,a[i].y);

    memset(bz,1,sizeof(bz));
    for(int i=1;i<=m1;i++)
        bfs(b[i].y);
    for(int i=1;i<=n;i++)
        if(!bz[i] && f[i]!=-123)
        {
            c[++m2].x=f[i];
            c[m2].y=i;
        }

    memset(mi,127,sizeof(mi));
    memset(mx,128,sizeof(mx));
    sort(c+1,c+1+m2,cmp);
    mx[0]=mi[0]=0;
    for(int i=1;i<=m2;i++)
        mi[c[i].y]=mx[c[i].y]=mx[c[i-1].y]+1;

    memset(last,0,sizeof(last));tot=0;
    for(int i=1;i<=w;i++)
        if((a[i].x!=a[i-1].x || a[i].y!=a[i-1].y)&&(!bz[a[i].x] && !bz[a[i].y]))ins(a[i].y,a[i].x);

    memset(bz,1,sizeof(bz));
    for(int i=1;i<=m2;i++)
        bfs1(c[i].y);
    memset(bz,1,sizeof(bz));
    for(int i=m2;i;i--)
        bfs2(c[i].y);

    for(int i=1;i<=m1;i++)
    {
        if(mi[b[i].y]>inf || mx[b[i].y]<-inf)P('0');else write(mx[b[i].y]-mi[b[i].y]+1);
        P('\n');
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值