3832: [Poi2014]Rally
3832: [Poi2014]Rally
分析:
首先可以考虑删除掉一个点后,计算最长路。
设$f[i]$表示从起点到i的最长路,$g[i]$表示从i出发到终点的最长路。那么经过一条边的最长路就是$f[u]+1+g[v]$。
删除一个点x后,会使一些路径没了。考虑这些路径的特点。我们它比x拓扑序小的设为集合S,拓扑序大的设为T。
1、如果以前的一条路径经过x,那么去掉x后,考虑如何去掉这些路径的影响。只需将x的入边删掉就行了。
2、那么如何统计新的答案,并且新的路径不能经过x。此处是一个有意思的地方,统计所有起点在S,终点在T的所有边,会发现所有经过这些边的路径都不会经过x。(这些路径中一般是起代替x的作用的,但是存在一些边并没有代替x,但是对答案不影响)。
那么做法就出来了:按照拓扑序删点,不断维护起点在S,终点在T的边,每条边权值为$f[u]+1+g[v]$,取最大值。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 500005; int g[N], f[N], T[N << 2], cnt[N << 2], q[N], n; struct Edge{ int to[N << 1], nxt[N << 1], head[N], En, deg[N << 1]; inline void add_edge(int u,int v) { ++En; to[En] = v, nxt[En] = head[u]; head[u] = En; deg[v] ++; } }Z, F; void solve() { int L = 1, R = 0; for (int i = 1; i <= n; ++i) if (F.deg[i] == 0) q[++R] = i; while (L <= R) { int u = q[L ++]; for (int i = F.head[u]; i; i = F.nxt[i]) { int v = F.to[i]; g[v] = max(g[v], g[u] + 1); if (!(--F.deg[v])) q[++R] = v; } } L = 1, R = 0; for (int i = 1; i <= n; ++i) if (Z.deg[i] == 0) q[++R] = i; while (L <= R) { int u = q[L ++]; for (int i = Z.head[u]; i; i = Z.nxt[i]) { int v = Z.to[i]; f[v] = max(f[v], f[u] + 1); if (!(--Z.deg[v])) q[++R] = v; } } } void update(int l,int r,int rt,int p,int v) { if (l == r) { cnt[rt] += v; if (cnt[rt] > 0) T[rt] = l; else T[rt] = -1, cnt[rt] = 0; return ; } int mid = (l + r) >> 1; if (p <= mid) update(l, mid, rt << 1, p, v); else update(mid + 1, r, rt << 1 | 1, p, v); T[rt] = max(T[rt << 1], T[rt << 1 | 1]); } int main() { n = read();int m = read(); for (int i = 1; i <= m; ++i) { int x = read(), y = read(); Z.add_edge(x, y); F.add_edge(y, x); } solve(); int ans = 1e9, pt; for (int i = 1; i <= n; ++i) update(0, n, 1, g[i], 1); for (int i = 1; i <= n; ++i) { int x = q[i]; for (int j = F.head[x]; j; j = F.nxt[j]) update(0, n, 1, g[x] + f[F.to[j]] + 1, -1); update(0, n, 1, g[x], -1); if (T[1] < ans) ans = T[1], pt = x; for (int j = Z.head[x]; j; j = Z.nxt[j]) update(0, n, 1, f[x] + g[Z.to[j]] + 1, 1); update(0, n, 1, f[x], 1); } cout << pt << " " << ans; return 0; }