P3573 [POI2014] RAJ-Rally

P3573 [POI2014] RAJ-Rally

[POI2014] RAJ-Rally

题面翻译

题目描述

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

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

输入格式&&数据范围

第一行包含两个正整数 \(n\)\(m\)\(2\le n\le5\times10^5\)\(1\le m\le10^6\)),表示点数、边数。

接下来 \(m\) 行每行包含两个正整数 \(a_i,b_i\)\(1\le a_i,b_i\le n,a_i\ne b_i\)),表示 \(a_i\)\(b_i\) 有一条边。

Solution:

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

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

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

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

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

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

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

1.\(dis_{st_u}\)
2.\(dis_{ed_u}\)
3.\(dis_{ed_u}+dis_{st_v}  (u,v) \in 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 @ 2024-12-25 21:49  liuboom  阅读(23)  评论(0)    收藏  举报