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

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 4000001
struct 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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值