P3573 [POI2014] RAJ-Rally
P3573 [POI2014] RAJ-Rally
[POI2014] RAJ-Rally
题面翻译
题目描述
给定一个
请找到一个点,使得删掉这个点后剩余的图中的最长路径最短。
输入格式&&数据范围
第一行包含两个正整数
接下来
Solution:
是图论思维题捏 由于是 DAG 所以我们能直接拓扑,在
具体的:我们在存图时存一张原图
然后我们就跑出这整个图的拓扑序列
对于
对于
然后我们开始思考如何统计答案:
对于一个点,它可能产生三种贡献:
1.
2.
3.
然后我们想要删除一个点的话只要删掉以上三种贡献就好了
那么我们这么维护呢?
我们维护一个类似可删优先队列的东西,并且我们只关注堆顶,并且只会查询
虽然可删的优先队列并不存在,但是上述数据结构可以用两个优先队列
然后这题就愉快的写完了
Code
#include<bits/stdc++.h> const int N=1e6+5; const int inf=1e9; using namespace std; inline int Max(int x,int y){return x > y ? x : y;} inline int Min(int x,int y){return x < y ? x : y;} vector<int> E[N],e[N]; int n,m,ans=inf,pos; int V[N],dis_st[N],dis_ed[N],d[N]; queue<int> q; struct Queue{ priority_queue<int> A,B; void add(int x){A.push(x);} void del(int x){B.push(x);} void calc(){while(!A.empty()&&!B.empty()&&A.top()==B.top()){A.pop(),B.pop();}} }Q; void work() { cin>>n>>m; for(int i=1,x,y;i<=m;i++) { scanf("%d%d",&x,&y); E[x].emplace_back(y); e[y].emplace_back(x);d[y]++;//out } for(int u=1;u<=n;u++) { if(!d[u])q.push(u); } while(!q.empty()) { int u=q.front();q.pop(); V[++V[0]]=u; for(auto v : E[u])if(--d[v]==0)q.push(v); } for(int i=1;i<=V[0];i++) { int u=V[i]; for(auto v : E[u])dis_ed[v]=Max(dis_ed[u]+1,dis_ed[v]); } for(int i=V[0];i;i--) { int u=V[i]; for(auto v : e[u])dis_st[v]=Max(dis_st[u]+1,dis_st[v]); } for(int i=1;i<=V[0];i++)Q.add(dis_st[i]); for(int i=1;i<=V[0];i++) { int u=V[i]; Q.del(dis_st[u]); for(auto v : e[u])Q.del(dis_ed[v]+1+dis_st[u]); Q.calc(); int tmp=inf; if(!Q.A.empty()); tmp=Q.A.top(); if(tmp<ans){ans=tmp,pos=u;} for(auto v : E[u])Q.add(dis_ed[u]+1+dis_st[v]); Q.add(dis_ed[u]); } printf("%d %d",pos,ans); } int main() { //freopen("P3573.in","r",stdin);freopen("P3573.out","w",stdout); work(); return 0; }