CSP/NOIP新赛制内部挑战赛1 D. 重建
sub2
对于每个时间m,跑一次tarjan,然后O(1)应对询问
时间复杂度:O(NM)
期望得分:36pts
代码
#include<bits/stdc++.h> using namespace std; #define PII pair<int,int> const int maxn=1e6+5; int n,m,q,cnt,col_num,head[maxn],qa[maxn],qb[maxn],a[maxn],b[maxn]; int dfn[maxn],low[maxn],col[maxn],times,top,s[maxn]; struct edge { int to,nxt; }e[maxn<<1]; void add(int x,int y) { e[++cnt].to=y; e[cnt].nxt=head[x]; head[x]=cnt; } void tarjan(int x) { low[x]=dfn[x]=++times; s[++top]=x; for(int i=head[x];i;i=e[i].nxt) { int to=e[i].to; if(!dfn[to]) { tarjan(to); low[x]=min(low[x],low[to]); } else if(!col[to]) low[x]=min(low[x],dfn[to]); } int v=-1; if(low[x]==dfn[x]) { ++col_num; do { v=s[top--]; col[v]=col_num; }while(v!=x); } } int ans[maxn]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=m;i++) scanf("%d%d",&a[i],&b[i]); for(int i=1;i<=q;i++) scanf("%d%d",&qa[i],&qb[i]); for(int i=1;i<=q;i++) { if(qa[i]!=qb[i]) ans[i]=-1; else ans[i]=0; } for(int i=1;i<=m;i++) { add(a[i],b[i]); for(int j=1;j<=n;j++) dfn[j]=col[j]=low[j]=0; times=top=col_num=0; for(int j=1;j<=n;j++) if(!dfn[j]) tarjan(j); for(int j=1;j<=q;j++) { if(ans[j]!=-1) continue; if(col[qa[j]]==col[qb[j]]) ans[j]=i; } } for(int i=1;i<=q;i++) printf("%d\n",ans[i]); return 0; }
sub4
观察到q比较小,这部分分时二分再加上bfs拿到的
标算
二分区间,加入小于等于mid的边
然后跑一次tarjan,对于一条边,如果它的出现时间≤ mid 并且被强连通分量缩起来
了,那么就把它放到(l, mid) 区间中,
否则就把它放到(mid + 1, r) 区间中。
对于一个询问,如果在mid 时刻已经u, v 已经可以互相到达了,那
么就把它放到(l, mid) 区间中,
否则就把它放到(mid + 1, r) 区间中。
先递归区间(l, mid),然后将所有强连通分量缩起来,变成一张新
图,再递归区间(mid + 1, r)。
这个代码实现的难度有点大啊,以后填坑吧