P3573 [POI2014] RAJ-Rally

P3573 [POI2014] RAJ-Rally

[POI2014] RAJ-Rally

题面翻译

题目描述

给定一个 n 个点 m 条边的有向无环图,每条边长度都是 1

请找到一个点,使得删掉这个点后剩余的图中的最长路径最短。

输入格式&&数据范围

第一行包含两个正整数 nm2n5×1051m106),表示点数、边数。

接下来 m 行每行包含两个正整数 ai,bi1ai,bin,aibi),表示 aibi 有一条边。

Solution:

是图论思维题捏 由于是 DAG 所以我们能直接拓扑,在O(n) 的时间内求出以每个点为起点/终点的最短路 disst,dised

具体的:我们在存图时存一张原图 E ,一张补图 e ,同时记录每个点的入度 du

然后我们就跑出这整个图的拓扑序列 V

对于dised: 我们顺序遍历整个 V 然后统计当前节点 u 对于其在原图 E 上的邻居 v 的贡献

对于disst: 我们逆序遍历整个 V 然后统计当前节点 u 对于其在反图 e 上的邻居 v 的贡献

然后我们开始思考如何统计答案:

对于一个点,它可能产生三种贡献:

1.disstu
2.disedu
3.disedu+disstv (u,v)E

然后我们想要删除一个点的话只要删掉以上三种贡献就好了

那么我们这么维护呢?

我们维护一个类似可删优先队列的东西,并且我们只关注堆顶,并且只会查询 n 次。

虽然可删的优先队列并不存在,但是上述数据结构可以用两个优先队列 A,B 维护,A 维护所求堆, B 维护删除堆。对于每次询问,将所有 B 中的元素尽可能地从 A 中删除

然后这题就愉快的写完了

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;
}
posted @   liuboom  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示