2018.11.03-dtoj-2092-交通 (traffic)

题目描述:

The center of Gdynia is located on an island in the middle of the Kacza river. Every morning thousands of cars drive through this island from the residential districts on the western bank of the river (using bridge connections to junctions on the western side of the island) to the industrial areas on the eastern bank (using bridge connections from junctions on the eastern side of the island).

The island resembles a rectangle, whose sides are parallel to the cardinal directions. Hence, we view it as an A × B rectangle in a Cartesian coordinate system, whose opposite corners are in points (0, 0) and (A,B). On the island, there are n junctions numbered from 1 to n. The junction number i has coordinates (xi, yi). If a junction has coordinates of the form (0, y), it lies on the western side of the island. Similarly, junctions with the coordinates (A, y) lie on the eastern side. Junctions are connected by streets. Each street is a line segment connecting two junctions. Streets can be either unidirectional or bidirectional. No two streets may have a common point (except for, possibly, a common end in a junction). There are are no bridges or tunnels. You should not assume anything else about the shape of the road network. In particular, there can be streets going along the river bank or junctions with no incoming or outgoing streets. Because of the growing traffic density, the city mayor has hired you to check whether the current road network on the island is sufficient.

He asked you to write a program which determines how many junctions on the eastern side of the island are reachable from each junction on the western side.

格丁尼亚的中心位于Kacza河中的一座岛屿。每天清晨,成千上万辆汽车通过岛屿从西岸的住宅区 (由桥连接岛的西部)到东岸的工业区(由桥连接岛的东部)。

该岛类似于矩形,它的边平行于主方向。故可将它看作是笛卡尔坐标系中的一个A*B的矩形,它的对角分别为(0, 0)和(A, B)。 岛上有n个交通节点,编号为1…n(junction, 此处可理解为广义的路口),第i个节点坐标为(xi, yi)。 如果一个节点的坐标为(0, y),它就位于岛的西岸。类似的,坐标为(A, y)的节点位于岛的东岸。 各个节点由街道连接,每条街道用线段连接两个节点。街道有单向行驶或双向行驶之分。除端点外任意两条街道都没有公共点。也没有桥梁或者隧道。 你不能对道路网络形状做任何其他假设。沿河岸的街道或节点可能没有入口或者出口街道。

由于交通堵塞日趋严重,市长聘请你测试岛上当前的道路网是否足够。要求你写一个程序确定从岛的西岸的每个节点能够到达东岸的多少个节点。

输入:

The first line of the standard input contains four integers n, m, A and B (1 <= n <= 300 000, 0 <= m <= 900 000, 1 <= A,B <= 10^9). They denote the number of junctions in the center of Gdynia, the number of streets and dimensions of the island, respectively. In each of the following n lines there are two integers xi, yi (0 <= xi <= A, 0 <= yi <= B) describing the coordinates of the junction number i. No two junctions can have the same coordinates. The next m lines describe the streets. Each street is represented in a single line by three integers ci, di, ki (1 <= ci, di <= n, ci ≠ di, ki ∈ {1, 2}). Their meaning is that junctions ci and di are connected with a street. If ki = 1, then this is a unidirectional street from ci to di. Otherwise, the street can be driven in both directions. Each unordered pair {ci, di} can appear in the input at most once. You can assume that there is at least one junction on the western side of the island from which it is possible to reach some junction on the eastern side of the island. Additionally, in test cases worth at least 30 points, n,m <= 6 000.

第1行包含4个整数n, m, A, B(1≤n≤300000, 0≤m≤900000,1≤A,B≤10^9),分别表示格丁尼亚市中心的节点数,街道数和岛屿的尺寸。

接下来的n行,每行包含两个整数xi,yi (0≤xi≤A,0≤yi≤B),表示第i个节点的坐标。任意两个节点的坐标都不相同。

再往下的m行表示街道,每条街道用3个整数ci, di, ki(1≤ci, di≤n, ci≠di, ki∈{1,2}),表示节点ci、di有街道连接。如果ki=1,表示从ci到di的街道是单向的,否则,这条街道可以双向行驶。

每个无序对{ci, di}最多出现1次。

你可以假设西岸节点中至少有1个能够到达东岸的一些节点。

输出:

Your program should write to the standard output one line for each junction on the western side of the island. This line should contain the number of junctions on the eastern side that are reachable from that junction. The output should be ordered according to decreasing y-coordinates of the junctions.

为每个西岸节点输出1行,包括从这个节点出发能够到达东岸的节点数目,

输出根据这些节点的y坐标降序排序。

数据范围:

至少有30分的测试数据,n, m≤6000。

1≤n≤300000, 0≤m≤900000,1≤A,B≤10^9

算法标签:BFS

思路:

这题的关键在于,题目说的不想交是指几何意义的不相交这意味着,除去不连通的点外,左边每个点连到右边一个区间的点,根据这个性质,我们可以除去不连通的点,然后在右边先从上自下bfs,每个能被第一次遍历到的点即其最小编号确定,再从下自上遍历求其最大编号,于是每个点所能达到的右边区间点的个数几位maxn-minn+1.共计三遍bfs代码长度或速度都优于tarjan

以下代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define il inline
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=3e5+5,M=9e5+5,inf=1e9;
bool vis[N];
struct node{int y,id;}p1[N],p2[N];
struct data{int op,l,r;}t[M];
int head[N],ne[M<<1],to[M<<1],cnt,tot,val[N];
int n,m,a,b,tot1,tot2,maxn[N],minn[N];
il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
il void insert(int x,int y){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;}
bool cmp(node t1,node t2){return t1.y<t2.y;}
bool cmp1(node t1,node t2){return t1.y>t2.y;}
void dfs(int x){
    vis[x]=1;
    for(int i=head[x];i;i=ne[i])
        if(!vis[to[i]])dfs(to[i]);
}
void dfs1(int x,int val){
    minn[x]=val;
    for(int i=head[x];i;i=ne[i]){
        if(!minn[to[i]])dfs1(to[i],val);
    }
}
void dfs2(int x,int val){
    maxn[x]=val;
    for(int i=head[x];i;i=ne[i]){
        if(!maxn[to[i]])dfs2(to[i],val);
    }
}
int main()
{
    n=read();m=read();a=read();b=read();
    for(int i=1;i<=n;i++){
        int x=read(),y=read();
        if(x==0)p1[++tot1]=(node){y,i};
        else if(x==a)p2[++tot2]=(node){y,i};
    }
    for(int i=1;i<=m;i++){
        int x=read(),y=read(),op=read();
        if(op==1)insert(x,y);
        else insert(x,y),insert(y,x);
        t[i].l=x;t[i].r=y;t[i].op=op;
    }
    sort(p2+1,p2+1+tot2,cmp);tot=0;
    for(int i=1;i<=tot1;i++)dfs(p1[i].id);
    for(int i=1;i<=tot2;i++){
        int x=p2[i].id;
        if(!vis[x])continue;
        val[x]=++tot;
    }
    for(int i=1;i<=n;i++)head[i]=0;cnt=0;
    for(int i=1;i<=m;i++){
        if(t[i].op==1){
            insert(t[i].r,t[i].l);
        }
        else{
            insert(t[i].r,t[i].l);
            insert(t[i].l,t[i].r);
        }
    }
    for(int i=1;i<=tot2;i++)if(val[p2[i].id])dfs1(p2[i].id,val[p2[i].id]);
    for(int i=tot2;i;i--)if(val[p2[i].id])dfs2(p2[i].id,val[p2[i].id]);
    sort(p1+1,p1+1+tot1,cmp1);
    for(int i=1;i<=tot1;i++){
        if(maxn[p1[i].id]==0)puts("0");
        else printf("%d\n",maxn[p1[i].id]-minn[p1[i].id]+1);
    }
  return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Jessie-/p/9901415.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进课程实践、课外项目或毕业设计。通过分析和运源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值