【POI2014】RAJ-Rally

题面

https://www.luogu.org/problem/P3573

题解

拓扑排序神仙题。

因为是$DAG$,所以拓扑排序搞出拓扑序。

在正反两遍$dp$搞出$f[x]$和$g[x]$

再用类似扫描线的方法更新好了。

实现时传承$yyb$的题解,用了可删堆,实现方法和可删除的$AC$自动机一样,也可以用线段树(可能要在线段树上二分跑答案)

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 500500
#define ri register int
using namespace std;

int n,m,ru[N],tup[N],f[N],g[N];
vector<int> to[N],dt[N];

inline int read() {
  int ret=0,f=0; char ch=getchar();
  while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
  while (ch>='0' && ch<='9') ret*=10,ret+=(ch-'0'),ch=getchar();
  return f?-ret:ret;
}

struct keshandui {
  priority_queue<int> a,b;
  void push(int x) {
    a.push(x);
  }
  void del(int x) {
    b.push(x);
  }
  int top() {
    while (!a.empty() && !b.empty() && a.top()==b.top()) a.pop(),b.pop();
    return a.top();
  }
} q;

int main(){
  n=read(); m=read();
  for (ri i=1;i<=m;i++) {
    int u=read(),v=read();
    to[u].push_back(v); dt[v].push_back(u);
    ru[v]++;
  }
  queue<int> Q;
  for (ri i=1;i<=n;i++) if (!ru[i]) Q.push(i);
  int cc=0;
  while (!Q.empty()) {
    int x=Q.front(); Q.pop();
    tup[++cc]=x;
    for (ri i=0;i<to[x].size();i++) {
      int y=to[x][i];
      ru[y]--;
      if (!ru[y]) Q.push(y);
    }
  }
  for (ri i=1;i<=n;i++) {
    int x=tup[i];
    for (ri j=0;j<to[x].size();j++) if (f[x]+1>f[to[x][j]]) f[to[x][j]]=f[x]+1;
  }
  for (ri i=n;i>=1;i--) {
    int x=tup[i];
    for (ri j=0;j<to[x].size();j++) if (g[to[x][j]]+1>g[x]) g[x]=g[to[x][j]]+1;
  }
  for (ri i=1;i<=n;i++) q.push(g[tup[i]]);
  int ans1=n+1,ans2=-1;
  for (ri i=1;i<=n;i++) {
    int x=tup[i];
    q.del(g[x]);
    for (ri j=0;j<dt[x].size();j++) q.del(f[dt[x][j]]+g[x]+1);
    if (q.top()<ans1) ans1=q.top(),ans2=x;
    q.push(f[x]);
    for (ri j=0;j<to[x].size();j++) q.push(f[x]+g[to[x][j]]+1);
  }
  printf("%d %d
",ans2,ans1);
}
原文地址:https://www.cnblogs.com/shxnb666/p/11298468.html