jzoj3577 [CEOI2011]Traffic 强连通分量缩点

来源:互联网 发布:impress.js demo 编辑:程序博客网 时间:2024/05/16 19:21

Description


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

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

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

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

Solution


注意到一个条件是没有两条边相交,那么我们把东岸的点按y坐标降序排列后,任意一个西岸的点能到达的东岸一定是连续的一段。tarjan缩点之后求出一个起点能到达的最大和最小标号的终点即可

本来还以为会爆栈的= =!

Code


#include <stdio.h>#include <string.h>#include <stack>#include <algorithm>#include <queue>#define rep(i,st,ed) for (int i=st;i<=ed;++i)#define fill(x,t) memset(x,t,sizeof(x))#define read2(x,y) read(x),read(y)#define read3(x,y,z) read(x),read(y),read(z)#define max(x,y) ((x)>(y)?(x):(y))#define min(x,y) ((x)<(y)?(x):(y))#define INF 0x3f3f3f3f#define N 600001#define E 4000001struct edge{int x,y,next;}e[E];struct pos{int x,y;}p[N];std:: queue<int>que;std:: stack<int>stack;int id[N],inStack[N],dfn[N],low[N],scc[N],data[N],vis[N];int mn[N],mx[N];int ls[N],edCnt=0;int n,m,A,B;void read(int &x) {    x=0; int v=1; char ch=getchar();    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());    x*=v;}void addEdge(int x,int y) {    e[++edCnt]=(edge){x,y,ls[x]}; ls[x]=edCnt;}void dfs(int now) {    if (vis[now]) return ;    vis[now]=1;    for (int i=ls[now];i;i=e[i].next) dfs(e[i].y);}void tarjan(int now) {    stack.push(now);    inStack[now]=1;    dfn[now]=low[now]=++dfn[0];    for (int i=ls[now];i;i=e[i].next) {        if (!dfn[e[i].y]) {            tarjan(e[i].y);            low[now]=min(low[now],low[e[i].y]);        } else if (!scc[e[i].y]) {            low[now]=min(low[now],dfn[e[i].y]);        }    }    if (dfn[now]==low[now]) {        ++scc[0];        mx[scc[0]]=-INF;        mn[scc[0]]=INF;        for (int tmp=0;tmp!=now;) {            tmp=stack.top(); stack.pop();            if (id[tmp]) {                mx[scc[0]]=max(mx[scc[0]],id[tmp]);                mn[scc[0]]=min(mn[scc[0]],id[tmp]);            }            scc[tmp]=scc[0];            inStack[tmp]=0;        }    }}bool cmp(int a,int b) {return p[a].y>p[b].y;}void dp(int now) {    if (vis[now]) return ;    vis[now]=1;    for (int i=ls[now];i;i=e[i].next) {        dp(e[i].y);        mx[now]=max(mx[now],mx[e[i].y]);        mn[now]=min(mn[now],mn[e[i].y]);    }}int main(void) {    read2(n,m); read2(A,B);    rep(i,1,n) {read2(p[i].x,p[i].y);}    rep(i,1,m) {        int x,y,opt;        read3(x,y,opt);        addEdge(x,y);        if (opt!=1) {addEdge(y,x);}    }    int cnt=0;    rep(i,1,n) if (!p[i].x) dfs(i);    rep(i,1,n) if (p[i].x==A&&vis[i]) data[++cnt]=i;    std:: sort(data+1,data+cnt+1,cmp);    rep(i,1,cnt) {id[data[i]]=i;}    rep(i,1,n) if (!dfn[i]) {tarjan(i);}    fill(ls,0); int tmp=edCnt;    rep(i,1,tmp) if (scc[e[i].x]!=scc[e[i].y]) {        addEdge(scc[e[i].x],scc[e[i].y]);    }    fill(vis,0);    rep(i,1,scc[0]) dp(i);    cnt=0;    rep(i,1,n) if (!p[i].x) {data[++cnt]=i;}    std:: sort(data+1,data+cnt+1,cmp);    rep(i,1,cnt) {        printf("%d\n", max(0,mx[scc[data[i]]]-mn[scc[data[i]]]+1));    }    return 0;}