P11352 题解
DaiRuiChen007 · · 题解
Problem Link
题目大意
给定
n 个点m 条边的 DAG,对于每个u 求最小的i 使得保留前i 条边后u 的拓扑序唯一。数据范围:
n\le 2\times 10^5,m\le 8\times 10^5 。
思路分析
首先考虑什么样的
考虑第一个条件,只保留拓扑序小等于
同理保留拓扑序大于等于
那么动态维护前缀或后缀的导出子图上每个点的最小出边,用堆维护答案即可。
时间复杂度
代码呈现
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+5,MAXM=8e5+5;
int n,m,a[MAXN],deg[MAXN];
struct Edge { int v,w; };
vector <Edge> L[MAXN],R[MAXN];
int f[MAXN],g[MAXN];
signed main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1,u,v;i<=m;++i) {
cin>>u>>v,++deg[v],L[u].push_back({v,i}),R[v].push_back({u,i});
}
queue <int> Q;
for(int i=1;i<=n;++i) if(!deg[i]) Q.push(i);
for(int i=1;i<=n;++i) {
int u=a[i]=Q.front(); Q.pop();
for(auto e:L[u]) if(!--deg[e.v]) Q.push(e.v);
}
priority_queue <array<int,2>> S;
for(int i=n;i>=1;--i) {
int u=a[i];
for(auto e:L[u]) if(e.w<g[e.v]) S.push({g[e.v]=e.w,e.v});
while(S.size()) {
auto it=S.top();
if(it[0]!=g[it[1]]) S.pop();
else { f[u]=max(f[u],it[0]); break; }
}
S.push({g[u]=m+1,u});
}
priority_queue<array<int,2>>().swap(S);
for(int i=1;i<=n;++i) {
int u=a[i];
for(auto e:R[u]) if(e.w<g[e.v]) S.push({g[e.v]=e.w,e.v});
while(S.size()) {
auto it=S.top();
if(it[0]!=g[it[1]]) S.pop();
else { f[u]=max(f[u],it[0]); break; }
}
S.push({g[u]=m+1,u});
}
for(int i=1;i<=n;++i) cout<<(f[i]>m?-1:f[i])<<" \n"[i==n];
return 0;
}