bzoj3832 Rally
Rally
题目描述
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 U to intersection V , then it is definitely impossible to get from V to U.
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 possible.
给定一个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],B[i](1<=A[i],B[i]<=N,A[i]<>B[i]),表示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后图中的最长路径的长度,如果有多组解请输出任意一组。
样例输入
<span style="color:#333333"><span style="color:#333333">6 5
1 3
1 4
3 6
3 4
4 5
</span></span>
样例输出
<span style="color:#333333"><span style="color:#333333">1 2</span></span>
提示
来源
solution
先用两遍拓扑序求出f[i]表示到达i的最长路,g[i]表示从i出发的最长路。
假设我们有两个集合S,T,T存每一个点出发的最长路,S为到达每个点最长路。
一开始所有点都是在T集合中。
我们考虑按拓扑序把点提出来,假装删去。
那就删除进入它的所有边,和它出发的最长边。
然后加入他出发的所有边,并把它加入S集里。
线段树维护
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define maxn 500005
using namespace std;
int n,m,t1,t2,head[maxn],Head[maxn],tot,in[maxn],out[maxn];
int order[maxn],top,ans,ansi,f[maxn],g[maxn];
queue<int>q;
struct node{
int v,nex;
}e[1000006],E[1000006];
struct no{
int v,pl;
}tree[maxn*4];
void lj(int t1,int t2){
e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
E[tot].v=t1;E[tot].nex=Head[t2];Head[t2]=tot;
}
void update(int k,int l,int r,int p,int val){
if(l==r){
tree[k].v+=val;
if(tree[k].v>0)tree[k].pl=p;
else tree[k].pl=0;
// v if exist
// pl value
return;
}
int mid=l+r>>1;
if(p<=mid)update(k<<1,l,mid,p,val);
else update(k<<1|1,mid+1,r,p,val);
tree[k].pl=max(tree[k*2].pl,tree[k*2+1].pl);
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
scanf("%d%d",&t1,&t2);
lj(t1,t2);in[t2]++;out[t1]++;
}
for(int i=1;i<=n;i++)if(!in[i])q.push(i);
while(!q.empty()){
int x=q.front();q.pop();order[++top]=x;
for(int i=head[x];i;i=e[i].nex){
in[e[i].v]--;f[e[i].v]=max(f[e[i].v],f[x]+1);
if(!in[e[i].v])q.push(e[i].v);
}
}
for(int i=1;i<=n;i++)if(!out[i])q.push(i);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=Head[x];i;i=E[i].nex){
out[E[i].v]--;g[E[i].v]=max(g[E[i].v],g[x]+1);
if(!out[E[i].v])q.push(E[i].v);
}
}
for(int i=1;i<=n;i++)update(1,0,n,g[i],1);
ans=1e9;
for(int i=1;i<=top;i++){
int x=order[i];
for(int j=Head[x];j;j=E[j].nex){
update(1,0,n,f[E[j].v]+1+g[x],-1);
}
update(1,0,n,g[x],-1);
if(tree[1].pl<ans)ans=tree[1].pl,ansi=x;
if(tree[1].pl==ans)ansi=min(x,ansi);
for(int j=head[x];j;j=e[j].nex){
update(1,0,n,f[x]+1+g[e[j].v],1);
}
update(1,0,n,f[x],1);
}
printf("%d %d\n",ansi,ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构