jzoj 3577. 【CEOI2011】Traffic

来源:互联网 发布:双机热备 数据库 编辑:程序博客网 时间:2024/05/16 23:44

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。

traffic解题报告(by jzoj)
【题目大意】
给出一个平面图,每个点的X坐标都在区间[0,A]内,每个点的Y坐标都在区间[0,B]内,没有重点。一些点之间有边,边分为双向边和单向边。要求问每个X=0的点能到达的不同的X=A的节点个数。
平面图有n个点,m条边,给出A,B,每个点的坐标,每条边连接的两个点和每条边的类型。n<=300000,m<=900000,A,B<=10^9。按照Y坐标递减的顺序输出每个X=0的点能到达的不同的X=A的节点个数。时限8s。
【题目关键字】
平面图,floodfill,BFS
【算法讨论】
这里写图片描述
如图,首先从每个所有X=0的点出发做一遍floodfill,然后把没有任何X=0的点能到达的X=A的节点删除。把所有X=A的节点按照Y坐标从小到达排序,因为该图是平面图,所以每个点能到达的X=A的节点一定是连续的一段。那么按照Y递增的顺序从每个X=A的节点出发在反图上做一遍floodfill,然后按照Y递减的顺序从每个X=A的节点出发在反图上做一遍floodfill,记录下两次过程中每个被染色的时间,即可算出每个点可达的X=A的节点数。
因为这题n较大,所以floodfill最好用BFS实现。BFS总的时间复杂度为O(n+m),排序操作总的时间复杂度为O(nlogn),最后总的时间复杂度为O(m+nlogn),对于8s的时限可以轻松通过本题。
【时空复杂度】
时间复杂度:O(m+nlogn)
空间复杂度:O(n)

代码:

# include <cstdlib>  # include <cstdio>  # include <cmath>  # include <cstring>  using namespace std;  const int maxn=300000+10, maxm=900000+10, oo=1073741819;  int top,top2,link2[maxm*3], next2[maxm*3], sum2[maxm*3],linke[maxm*3], next[maxm*3], sum[maxm*3];  int low[maxn], dfn[maxn], w[maxn],st[maxn];  bool step[maxn], stay[maxn];  int id[maxn], place[maxn], pt[maxn], pe[maxn], pb[maxn],l[maxn], r[maxn];  int n,m,A,B,tot,time;  void link(int x, int y) {++top; next[top]=linke[x]; linke[x]=top; sum[top]=y;};  inline int min(int x, int y) {return x<y?x:y;};  inline int max(int x, int y) {return x>y?x:y;};  void tarjan(int p)  {    int ke=linke[p],now;low[p]=dfn[p]=++time;st[++tot]=p; step[p]=true; stay[p]=true;    for (;ke!= 0; ke=next[ke])      if (!step[sum[ke]]) tarjan(sum[ke]), low[p]=min(low[p], low[sum[ke]]);        else if (stay[sum[ke]]) low[p]=min(low[p], dfn[sum[ke]]);    if (dfn[p]==low[p])    {      for (now=st[tot];now!=p;now=st[--tot])        id[now]=p, w[p]+= w[now], stay[now]=false, l[p]=min(l[p],l[now]), r[p]=max(r[p],r[now]);      tot--; stay[now]=false;    }  }  void dfs(int p)  {    int ke=link2[p]; step[p]=true;    for (;ke!=0; ke=next2[ke])    {      if (!step[sum2[ke]])        dfs(sum2[ke]), step[sum2[ke]]=true;      r[p]=max(r[p], r[sum2[ke]]); l[p]=min(l[p],l[sum2[ke]]);    }  }  void sort(int pt[maxn], int l, int r)  {    int i=l, j=r, tmp,d=place[pt[l+r>>1]];    for (;i <= j;)    {      for (;place[pt[i]] < d;i++);      for (;place[pt[j]] > d;j--);      if (i <= j) tmp=pt[i],pt[i]=pt[j],pt[j]=tmp,i++,j--;    }    if (i<r) sort(pt,i,r);    if (l<j) sort(pt,l,j);  }  void linke2(int x, int y)   {  ++top2; next2[top2]=link2[x];link2[x]=top2;sum2[top2]=y;  };  void dfs2(int p)  {    step[p]= true;    for (int ke=link2[p]; ke!= 0; ke=next2[ke])       if (!step[sum2[ke]])dfs2(sum2[ke]);  }  void prepare()  {    int i,x,y,z;  sort(pt,1,pt[0]); sort(pb,1,pb[0]);    for (i = 1; i <= m; i++)    {      scanf("%d%d%d",&x, &y, &z);      linke2(x,y); if (z==2) linke2(y,x);    }    for (i = 1; i <= pt[0]; i++) dfs2(pt[i]);    for (i = 1; i <= n; i++)       for (int ke=link2[i]; ke!= 0; ke=next2[ke])        if (step[i] && step[sum2[ke]]) link(i, sum2[ke]);     for (i = 1; i <=pb[0]; i++)      if (step[pb[i]]) pe[++pe[0]] = pb[i], l[pb[i]]=r[pb[i]]=pe[0];     memset(next2, 0, sizeof(next2));    memset(sum2, 0, sizeof(sum2));    memset(link2, 0, sizeof(link2));    memset(step, 0, sizeof(step)); top2=0;  }  int main()  {    int i,x,y;    //freopen("traffic.in", "r", stdin);    //freopen("traffic.out", "w", stdout);    scanf("%d%d%d%d", &n, &m, &A, &B);    for (i = 1; i <= n; i++)    {      scanf("%d%d", &x, &y); place[i]=y; l[i]=oo; r[i]=-oo;      if (x==0) pt[++pt[0]]=i; else if (x==A) pb[++pb[0]]=i;    }    prepare();    memset(step, false, sizeof(step));    for (i =1; i <= n; i++) id[i]=i;    for (i = 1; i <= n; i++)      if (!step[i]) tarjan(i);    memset(step, false, sizeof(step));    for (i = 1; i <= n; i++)      for (int ke=linke[i]; ke!= 0; ke=next[ke])        if (id[i]!= id[sum[ke]]) linke2(id[i], id[sum[ke]]);    for (i = 1; i <= n; i++)      if (!step[i]) dfs(i);    for (i = pt[0]; i >= 1; i--)      if (r[id[pt[i]]] != -oo) printf("%d\n", r[id[pt[i]]]-l[id[pt[i]]]+1); else printf("0\n");    return 0;  }  
原创粉丝点击