【题目】
原题地址
给定一个N个点M条边的有向无环图,每条边长度都是1。
请找到一个点,使得删掉这个点后剩余的图中的最长路径最短。
【题目分析】
首先这是一个DAG,我们还是很容易联想到DAG的一些特性,比如Topsort之类的,在这题就很有用了qwq。
【解题思路】
首先当然是建超级源超级汇。
因为这是一个DAG,所以我们就跑一下dp,算出源点到所有点的最长路(记作
f
f
)以及所有点到汇的最长路(记作)。
令边
x−>y
x
−
>
y
的权值为
f[x]+g[y]
f
[
x
]
+
g
[
y
]
,那么图的最长链转化为边权最大值。
接下来我们要做的就是枚举删哪个点,然后用数据结构维护一下删点后割集中最大边权。
考虑DAG的特性,我们还是可以用一下拓扑排序,发现按拓扑序进行删点就行了。
令初始
S
S
集只有,所有点和
T
T
都在集
按照拓扑序依次将每个点从
T
T
集中删掉,加入集
首先将这个点的所有入边从数据结构中删掉 此时割集的边权最大值就是删掉这个点的答案。
然后再将这个点的所有出边加入数据结构中即可。
这个插入、删除、查询,用堆就行了(不要问我怎么删除,开一个新的堆就行了),当然看到有人写线段树也是可以的qwq。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
const int N=5e5+10;
const int M=2e6+10;
int n,m,h,t,mn,ans;
int du[M],qs[M],w[M];
priority_queue<int>p,q;
struct Tst
{
int u[M],v[M],nex[M],head[N],dis[N],du[N],tot;
inline void add(int x,int y)
{
++tot;
u[tot]=x;v[tot]=y;
nex[tot]=head[x];head[x]=tot;
}
inline void solve(int S)
{
memset(dis,0,sizeof(dis));
h=t=1;qs[1]=S;
while(h<=t)
{
int x=qs[h++];
for(int i=head[x];i;i=nex[i])
{
int y=v[i];
dis[y]=max(dis[y],dis[x]+1);
du[y]--;
if(!du[y])
qs[++t]=y;
}
}
}
};
Tst A,B;
inline void dele(int x)
{
q.push(x);
while(!p.empty() && !q.empty() && q.top()==p.top())
{
q.pop();
p.pop();
}
}
int read()
{
int x=0;char c='.';
while(c<'0' || c>'9')
c=getchar();
while(c>='0' && c<='9')
{
x=x*10+(c-'0');
c=getchar();
}
return x;
}
int main()
{
// freopen("BZOJ3832.in","r",stdin);
// freopen("BZOJ3832.out","w",stdout);
n=read();m=read();
for(int i=1;i<=m;++i)
{
int u,v;
u=read();v=read();
du[v]++;A.du[v]++;B.du[u]++;
A.add(u,v);B.add(v,u);
}
for(int i=1;i<=n;++i)
{
du[i]++;du[n+1]++;
A.du[i]++;A.du[n+1]++;
B.du[i]++;B.du[0]++;
A.add(0,i);A.add(i,n+1);
B.add(i,0);B.add(n+1,i);
}
A.solve(0);B.solve(n+1);
for(int i=1;i<=m+2*n;++i)
w[i]=A.dis[A.u[i]]+B.dis[A.v[i]]-1;
h=t=1;qs[1]=0;
mn=INF;
while(h<=t)
{
int x=qs[h++];
for(int i=B.head[x];i;i=B.nex[i])
dele(w[i]);
if(x!=0 && x!=n+1)
{
int y=p.top();
if(y<mn)
mn=y,ans=x;
}
for(int i=A.head[x];i;i=A.nex[i])
{
int y=A.v[i];
p.push(w[i]);
du[y]--;
if(!du[y])
qs[++t]=y;
}
}
printf("%d %d\n",ans,mn);
return 0;
}
【总结】
这道题挺不错的qwq,然后我因为memset的数组空间开成了4倍,所以…TLE了两发。
DAG的特性牢记在心。