正题
题目链接:https://www.luogu.com.cn/problem/P3573
题目大意
个点条边的,删掉一个点使得最长路最短。
解题思路
先跑一遍拓扑排序
表示以结尾的最长路,表示以开头的最长路,用拓扑序+dp可以搞定
定义两个点集和,我们先将所有所有点放入集合,并且把放入一个数据结构里。
然后按照拓扑序枚举从小到大删除哪个点,枚举到的点我们把从数据结构里删除,对于我们可以把从数据结构里删除。
然后查询最小值统计答案
之后把和对于我们有都丢进数据结构里。
这里用树状数组+二分统计答案。
时间复杂度
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define lowbit(x) (x&-x)
using namespace std;
const int N=1e6+10;
struct node{
int to,next;
}a[N];
queue<int> q;
int n,m,cnt,ans,id;
int in[N],top[N],ds[N],dt[N],ls[N];
vector<int> init[N];
struct Tree_Array{
int t[N];
void Change(int x,int val){
if(!x) return;
while(x<=m){
t[x]+=val;
x+=lowbit(x);
}
return;
}
int Ask(int x){
int ans=0;
while(x){
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
int Maxs(){
int z=Ask(m);
int l=0,r=m;
while(l<=r){
int mid=(l+r)>>1;
if(Ask(mid)==z)r=mid-1;
else l=mid+1;
}
return l;
}
}T;
void Top_Sort(){
for(int i=1;i<=n;i++)
if(!in[i])q.push(i),top[++cnt]=i;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;in[y]--;
if(!in[y])q.push(y),top[++cnt]=y;
}
}
return;
}
void Get_Dis(){
for(int i=1;i<=n;i++){
int x=top[i];
for(int j=ls[x];j;j=a[j].next){
int y=a[j].to;
ds[y]=max(ds[y],ds[x]+1);
}
}
for(int i=n;i>=1;i--){
int x=top[i];
for(int j=0;j<init[x].size();j++){
int y=init[x][j];
dt[y]=max(dt[y],dt[x]+1);
}
}
return;
}
void Solve(){
ans=2147483647;
for(int i=1;i<=n;i++)
T.Change(dt[i],1);
for(int k=1;k<=n;k++){
int x=top[k];
T.Change(dt[x],-1);
for(int i=0;i<init[x].size();i++){
int y=init[x][i];
T.Change(ds[y]+dt[x]+1,-1);
}
int z=T.Maxs();
if(z<ans) ans=z,id=x;
T.Change(ds[x],1);
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
T.Change(ds[x]+dt[y]+1,1);
}
}
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
a[i].to=y;
a[i].next=ls[x];
ls[x]=i;in[y]++;
init[y].push_back(x);
}
Top_Sort();
Get_Dis();
Solve();
printf("%d %d",id,ans);
}
来源:CSDN
作者:ssl_wyc
链接:https://blog.csdn.net/Mr_wuyongcong/article/details/104114932