题目描述
An annual bicycle rally will soon begin in Byteburg.
The bikers of Byteburg are natural long distance cyclists.
Local representatives of motorcyclists, long feuding the cyclists, have decided to sabotage the event.
There are intersections in Byteburg, connected with one way streets.
Strangely enough, there are no cycles in the street network - if one can ride from intersection to intersection , then it is definitely impossible to get from to .
The rally's route will lead through Byteburg's streets.
The motorcyclists plan to ride their blazing machines in the early morning of the rally day to one intersection and completely block it.
The cyclists' association will then of course determine an alternative route but it could happen that this new route will be relatively short, and the cyclists will thus be unable to exhibit their remarkable endurance.
Clearly, this is the motorcyclists' plan - they intend to block such an intersection that the longest route that does not pass through it is as short as 给定一个N个点M条边的有向无环图,每条边长度都是1。
请找到一个点,使得删掉这个点后剩余的图中的最长路径最短。
输入输出格式
输入格式:
In the first line of the standard input, there are two integers, N and M(2<=N<=500 000,1<=M<=1 000 000), separated by a single space, that specify the number of intersections and streets in Byteburg. The intersections are numbered from to . The lines that follow describe the street network: in the -th of these lines, there are two integers, Ai, Bi(1<=Ai,Bi<=N,Ai<>Bi), separated by a single space, that signify that there is a one way street from the intersection no. Ai to the one no. Bi.
第一行包含两个正整数N,M(2<=N<=500 000,1<=M<=1 000 000),表示点数、边数。
接下来M行每行包含两个正整数A[i],Bi,表示A[i]到B[i]有一条边。
输出格式:
The first and only line of the standard output should contain two integers separated by a single space.
The first of these should be the number of the intersection that the motorcyclists should block, and the second - the maximum number of streets that the cyclists can then ride along in their rally.
If there are many solutions, your program can choose one of them arbitrarily.
包含一行两个整数x,y,用一个空格隔开,x为要删去的点,y为删除x后图中的最长路径的长度,如果有多组解请输出任意一组。
输入输出样例
输入样例#1: 复制
6 5
1 3
1 4
3 6
3 4
4 5
输出样例#1: 复制
1 2
题解
\(diss_u\) 表示以u点结束的最长路
\(dist_u\) 表示从u点开始的最长路
先拓扑排序求出 \(diss[] 和dist[]\)
然后建出dist的权值线段树
因为原图是一个DAG
所以按照拓扑序来更新答案
枚举每个要删的点
删掉经过这个点的所有路径然后再在权值线段树中查询最大值
但是这样要加入的边太多
所以要考虑优化
显然对于点u,ta的入边所连的点都不会被更新到了
所以先删\(dist[u]\)
所以只需要枚举ta的入边
删掉\(dist[u] + diss[v] + 1\)
查询一下最大值
然后再枚举ta的出边
加入\(diss[u] + dist[v] + 1\)
再加入\(diss[u]\)就好辣
代码
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define ls t[now].l
# define rs t[now].r
const int M = 500005 ;
const int INF = 1e8 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
int n , m , cnt , tot , rt ;
int Ans1 , Ans2 = INF , d[M] , diss[M] , dist[M] , id[M] ;
vector < int > e[M] , rev[M] ;
struct Node {
int l , r , sum ;
} t[M * 20] ;
inline void TopSort1() {
queue < int > q ;
for(int u = 1 ; u <= n ; u ++) for(int i = 0 , v ; i < e[u].size() ; i ++) {
v = e[u][i] ; ++ d[v] ;
}
for(int i = 1 ; i <= n ; i ++)
if(!d[i]) q.push(i) ;
while(!q.empty()) {
int u = q.front() ; q.pop() ; id[++cnt] = u ;
for(int i = 0 , v ; i < e[u].size() ; i ++) {
v = e[u][i] ;
diss[v] = max(diss[v] , diss[u] + 1) ;
-- d[v] ;
if(d[v] == 0) q.push(v) ;
}
}
}
inline void TopSort2() {
queue < int > q ; memset(d , 0 , sizeof(d)) ;
for(int u = 1 ; u <= n ; u ++) for(int i = 0 , v ; i < rev[u].size() ; i ++) {
v = rev[u][i] ; ++ d[v] ;
}
for(int i = 1 ; i <= n ; i ++)
if(!d[i]) q.push(i) ;
while(!q.empty()) {
int u = q.front() ; q.pop() ;
for(int i = 0 , v ; i < rev[u].size() ; i ++) {
v = rev[u][i] ;
dist[v] = max(dist[v] , dist[u] + 1) ;
--d[v] ;
if(d[v] == 0) q.push(v) ;
}
}
}
inline void pushup(int now) {
t[now].sum = t[ls].sum + t[rs].sum ;
}
void Insert(int x , int v , int l , int r , int &now) {
if(!now) now = ++tot ;
if(l == r) { t[now].sum += v ; return ; } ;
int mid = (l + r) >> 1 ;
if(mid >= x) Insert(x , v , l , mid , ls) ;
else Insert(x , v , mid + 1 , r , rs) ;
pushup(now) ;
}
int query(int l , int r , int now) {
if(l == r) return l ;
int mid = (l + r) >> 1 ;
if(t[rs].sum > 0) return query(mid + 1 , r , rs) ;
else return query(l , mid , ls) ;
}
int main() {
n = read() ; m = read() ;
for(int i = 1 , u , v ; i <= m ; i ++) {
u = read() , v = read() ;
e[u].push_back(v) ; rev[v].push_back(u) ;
}
TopSort1() ; TopSort2() ;
for(int i = 1 ; i <= n ; i ++) Insert(dist[i] , 1 , 1 , n , rt) ;
int temp = 0 ;
for(int i = 1 , u ; i <= n ; i ++) {
u = id[i] ;
Insert(dist[u] , -1 , 1 , n , rt) ;
for(int j = 0 , v ; j < rev[u].size() ; j ++) {
v = rev[u][j] ;
Insert(dist[u] + diss[v] + 1 , -1 , 1 , n , rt) ;
}
temp = query(1 , n , rt) ;
if(temp < Ans2) {
Ans2 = temp ; Ans1 = u ;
}
for(int j = 0 , v ; j < e[u].size() ; j ++) {
v = e[u][j] ;
Insert(diss[u] + dist[v] + 1 , 1 , 1 , n , rt) ;
}
Insert(diss[u] , 1 , 1 , n , rt) ;
}
printf("%d %d\n",Ans1 , Ans2) ;
return 0 ;
}