#2387. [Ceoi2011]Traffic

Online Judge:Bzoj-2387,Luogu-4700

Label:Yy,Tarjan缩点,dfs

题目描述

格丁尼亚的中心位于Kacza河中的一座岛屿。每天清晨,成千上万辆汽车通过岛屿从西岸的住宅区(由桥连接岛的西部)到东岸的工业区(由桥连接岛的东部)。该岛类似于矩形,它的边平行于主方向。故可将它看作是笛卡尔坐标系中的一个A*B的矩形,它的对角分别为(0, 0)和(A, B)。岛上有n个交通节点,编号为1…n(junction, 此处可理解为广义的路口),第i个节点坐标为(xi, yi)。如果一个节点的坐标为(0, y),它就位于岛的西岸。类似的,坐标为(A, y)的节点位于岛的东岸。各个节点由街道连接,每条街道用线段连接两个节点。街道有单向行驶或双向行驶之分。除端点外任意两条街道都没有公共点。也没有桥梁或者隧道。你不能对道路网络形状做任何其他假设。沿河岸的街道或节点可能没有入口或者出口街道。由于交通堵塞日趋严重,市长聘请你测试岛上当前的道路网是否足够。

要求你写一个程序确定从岛的西岸的每个节点能够到达东岸的多少个节点。

Luogu翻译d题面

输入格式

第1行包含4个整数n, m, A, B(\(1≤n≤300000, 0≤m≤900000,1≤A,B≤10^9\)),

分别表示格丁尼亚市中心的节点数,街道数和岛屿的尺寸。

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

再往下的m行表示街道,每条街道用3个整数\(c_i, d_i, k_i(1≤c_i, d_i≤n, c_i≠d_i, k_i∈{1,2})\),表示节点\(c_i、d_i\)有街道连接。如果\(k_i=1\),表示从\(c_i\)到\(d_i\)的街道是单向的,否则,这条街道可以双向行驶。每个无序对{\(c_i, d_i\)}最多出现1次。

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

输出格式

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

请按照y从大到小的顺序输出所有点对应的答案。

样例

输入

5 3 1 3
0 0
0 1
0 2
1 0
1 1
1 4 1
1 5 2
3 5 2

输出

2
0
2

题解:

首先对于同一个强连通分量里的点来说,他们能到达的东岸的点的个数是相同的。所以考虑Tarjan缩点,然后再重新建图,那么经过缩点后重建的图就不存在双向边了。

接下来怎么搞呢?

1.一种超好想然而会爆WA的\(O(N)\)思路:

对于每个节点i记录Dp[i],表示从i开始走能到达的东岸的点的个数。然后就是对整个图进行记忆化搜索。

\[Dp[x]=∑_{son∈x} Dp[son]
\]

但是这个方法存在一个问题,由于我们不一定从树根开始搜起,所以会出现重复计数的问题,例:如果x的两个儿子son1,son2都能到达某个东岸的点o,那么o就会被重复计数,所以答案是错误的。

2.一种超好想然而会爆T的\(O(N^2)\)思路:

就是缩完点之后,从每个西岸的点开始bfs、dfs都可,加上蜜汁优化卡常似乎可以跑过好多点。


AC做法:

第二种的\(O(N^2)\)肯定不可取,考虑如何修改第一种会WA的做法。

注意题面中一个非常非常重要的提示:除端点外任意两条街道都没有公共点。

结合下图,图中的每一个点都代表一个强连通分量。

我们发现,对于西岸的任意一点W来说,假设W所能访问到东岸的所有点中,高度最高的为ma,高度最低的为mi,则东岸中高度处于\([mi,ma]\)之间的点E,都可以被W访问到。

当然还有一个前提条件,就是E必须是能被西岸至少一个点访问到的,比如下图中东岸的C点,它就不能被西岸中至少一个点访问到,所以把像C这样的——在东岸却不能被至少一个在西岸的点,从东岸中剔除——因为他存不存在对答案没有影响,如何剔除呢,一个\(O(N)\)的dfs预处理就可以完成。

回过头看,当满足这个前提条件时,上面的发现必然成立,先来看看下图,比如对于点2来说,它对应的ma是B,对应的mi是D,那么高度处于B~D之间的必然也能被2访问到——(C由于不符合上面那个前提条件已经从东岸中剔除了)。

这个发现的正确性显而易见,如果存在某个未剔除的东岸的点它不满足条件,那么图中就会有两条线相交,而这不符合题目给定的那个提示,所以我们就可以根据这个性质来做了。

大致思路

  1. 剔除不能被西岸的点访问到的东岸的点,这里从西岸的每一个点开始dfs一遍,vis数组标记一下是否到过;
  2. 对东岸中剩余的点按照高度(纵坐标)从高到低排序——反一下也没关系;
  3. Tarjan缩点,跑的时候注意,如果加入当前强连通分量的点是东岸的点的话更新一下该强连通分量的ma,mi值;
  4. 重新建图,搜索整张图——(把图当作一棵普通的树,因为从左往右的边其实相当于没有),然后通过递归更新每个节点的ma,mi值。
  5. 排序一下西岸的每个点,依次输出,对于某点x来说,它的答案为\(ma[i]-mi[i]+1\)。

综上,由于存在排序,上述做法的时间复杂度为\(O(NlogN)\)。

当然这道题如果不缩点的话也可以,做法类似,只要通过题目读出隐藏性质转化问题就可以随便做了。

code☇

#include<bits/stdc++.h>
using namespace std;
#define debug(x) cout<<"####"<<x<<endl;
typedef pair<int,int> pii;
const int N=300010;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x;
}
pii p[N];
int A,B,n,m,idx,id[N];
vector<int>lp,rp,e[N],g[N];
bool vis[N];//vis:从西岸出发能否到达i
int pos[N],ma[N],mi[N];//ma/mi:某强连通分量能到达东岸的最高、低点
int dfn[N],low[N],ins[N],tot;
stack<int>s;
void tarjan(int x){
dfn[x]=low[x]=++tot;
s.push(x);ins[x]=1;
for(int i=0;i<e[x].size();i++){
int y=e[x][i];
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(ins[y])low[x]=min(low[x],dfn[y]);
}
int k;
if(low[x]==dfn[x]){
idx++;
do{
k=s.top();s.pop();
ins[k]=0,id[k]=idx;
if(p[k].first==A){
ma[idx]=max(ma[idx],pos[k]);
mi[idx]=min(mi[idx],pos[k]);
}
}while(x!=k);
}
}
void search(int x){
vis[x]=1;
for(int i=0;i<g[x].size();i++){
int y=g[x][i];
if(!vis[y])search(y);
ma[x]=max(ma[x],ma[y]);
mi[x]=min(mi[x],mi[y]);
}
}
void dfs(int x){
vis[x]=1;
for(int i=0;i<e[x].size();i++){
if(!vis[e[x][i]])dfs(e[x][i]);
}
}
inline bool cmp(int a,int b){return p[a].second>p[b].second;}
int main(){
memset(mi,0x3f,sizeof(mi)); n=read(),m=read(),A=read(),B=read();
for(int i=1;i<=n;i++){
int x=read(),y=read();
if(x==0)lp.push_back(i);
if(x==A)rp.push_back(i);
p[i]=make_pair(x,y);
} for(int i=1;i<=m;i++){
int u=read(),v=read();
e[u].push_back(v);
if(read()==2)e[v].push_back(u);
} for(int i=0;i<lp.size();i++)dfs(lp[i]); sort(rp.begin(),rp.end(),cmp);
int eastnum=0;
for(int i=0;i<rp.size();i++){
int y=rp[i];
if(vis[y])pos[y]=++eastnum;
} for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i); for(int i=1;i<=n;i++)for(int j=0;j<e[i].size();j++){
int y=e[i][j];
if(id[i]!=id[y]){
g[id[i]].push_back(id[y]);
}
}
memset(vis,0,sizeof(vis));
for(int i=1;i<=idx;i++)search(i); sort(lp.begin(),lp.end(),cmp);
for(int i=0;i<lp.size();i++){
int x=id[lp[i]];
printf("%d\n",max(0,ma[x]-mi[x]+1));
}
}

[Ceoi2011]Traffic的更多相关文章

  1. bzoj 2387: [Ceoi2011]Traffic

    bzoj 2387: [Ceoi2011]Traffic 题目描述 The center of Gdynia is located on an island in the middle of the ...

  2. Luogu4700 CEOI2011 Traffic Tarjan、搜索

    传送门 题意:给出平面上$N$个点,它们一定在左下角为$(0,0)$,右上角为$(A,B)$的一个矩形内的整点上(包括边界),而且会给出$M$条呈直线的边,其中有有向边也有无向边,保证任意两条边不会在 ...

  3. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  4. Linux下按程序查实时流量 network traffic

    实然看到下载速度多达几M/s,但实际上并没有什么占用带宽的进程. 相查看每个程序占用的网络流量, 但系统自带的 System Monitor 只能查看全局的流量, 不能具体看某个程序的...... k ...

  5. Windows Azure Traffic Manager (5) Traffic Manager Overview

    <Windows Azure Platform 系列文章目录> 笔者默默地看了一下之前写的Traffic Manager内容,已经差不多是3年前的文章了.现在Azure Traffic M ...

  6. Windows Azure Traffic Manager (6) 使用Traffic Manager,实现本地应用+云端应用的高可用

    <Windows Azure Platform 系列文章目录> 注意:本文介绍的是使用国内由世纪互联运维的Azure China服务. 以前的Traffic Manager,背后的Serv ...

  7. 流量工程 traffic engineering (TE)

    什么是流量工程 流量工程是指根据各种数据业务流量的特性选取传输路径的处理过程.流量工程用于平衡网络中的不同交换机.路由器以及链路之间的负载. [编辑] 流量工程的内容 流量工程在复杂的网络环境中,控制 ...

  8. snmp switch traffic交换机带宽

    上代码 <?php function getstr1($strall,$str1,$str2,$html_charset='utf-8'){ $i1=mb_strpos($strall,$str ...

  9. 每日英语:The Secret About Online Ad Traffic: One-Third Is Bogus

    Billions of dollars are flowing into online advertising. But marketers also are confronting an uncom ...

随机推荐

  1. java继承,多态

    子类继承父类,用父类去接收子类,其实我觉得用父类,子类来形容继承关系是不恰当的,比如再发生多态的时候,Car c = new W();w是大众,你能说Car 和W是父子关系吗,我觉得用所属关系类描述可 ...

  2. 0922CSP-S模拟测试赛后总结

    连发三篇爆炸实录我的心态竟然还这么好…… 昨天题目的D2.稍难. 这也不是我连续拿倒数第一的理由. T1不会.赛时硬写了一个30分的三次方暴力.还有一个地方写挂了.如果不是数据足够水我就爆零了. 也就 ...

  3. JSF(JavaServer Faces)简介

    JavaServer Faces (JSF) 是一种用于构建Java Web 应用程序的标准框架(是Java Community Process 规定的JSR-127标准).它提供了一种以组件为中心的 ...

  4. day 73 Django基础八之cookie和session

      Django基础八之cookie和session   本节目录 一 会话跟踪 二 cookie 三 django中操作cookie 四 session 五 django中操作session 六 x ...

  5. QT之QStatusBar

    1.QStatusBar一般处于主窗体(QMainWindow)的左下角用于显示比较重要的状态信息.我们通常调用其showMessage()函数 QT官方显示:[slot] void QStatusB ...

  6. Facebook分布式框架—Thrift介绍。

    Thrift介绍 Thrift是一个分布式RPC框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, ...

  7. 16.ajax_case07

    # 通过搜索接口抓取etherscan上的合约地址 # https://etherscan.io/ import requests import re header = { 'Accept': 'te ...

  8. 分布式日志收集之Logstash 笔记(一)

    (一)logstash是什么? logstash是一种分布式日志收集框架,开发语言是JRuby,当然是为了与Java平台对接,不过与Ruby语法兼容良好,非常简洁强大,经常与ElasticSearch ...

  9. 提问(prompt 消息对话框)用于询问一些需要与用户交互的信息。弹出消息对话框(包含一个确定按钮、取消按钮与一个文本输入框)

    提问(prompt 消息对话框) prompt弹出消息对话框,通常用于询问一些需要与用户交互的信息.弹出消息对话框(包含一个确定按钮.取消按钮与一个文本输入框). 语法: prompt(str1, s ...

  10. go string和[ ]byte

    https://www.cnblogs.com/zhangboyu/p/7623712.html