好久没有用 tarjan 了,今天做一道题,顺便复习一下
tarjan 是用来求连通性的算法,时间复杂度 O(n)。网上关于 tarjan 的博文很多,我这里就不写了,只是复习一下。
这道题很容易想到建边 i-a[i]:
对于长度是 k 的环,很显然可以满足;
对于长度不是 k 的环,无论如何都不能满足;
对于不构成环的点,可以随意向环中的点借位,因为不构成环,所以彼此互不影响,被借位的环中的点最后覆盖即可。
上代码:
#include<bits/stdc++.h> #define inf 1000000000 #define mod 998244353 using namespace std; const int N=1e6+10; int n,m,t,k,qq,tot,deep,sum,top; int f[N],dp[N],a[N],h[N],H[N],num[N]; int dfn[N],low[N],vis[N],Stack[N],color[N],cnt[N]; vector<int>e[N]; void tarjan(int u){ dfn[u]=low[u]=++deep; vis[u]=1; Stack[++top]=u; for(int v:e[u]){ if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ color[u]=++sum; vis[u]=0;num[sum]++; while(Stack[top]!=u){ num[sum]++; color[Stack[top]]=sum; vis[Stack[top--]]=0; } --top; } } void init(){ } void solve(){ cin>>n>>k; for(int i=1;i<=2*n;++i) dfn[i]=vis[i]=color[i]=num[i]=low[i]=Stack[i]=0; for(int i=1;i<=n*2;++i) e[i].clear(); deep=top=0; for(int i=1;i<=n;++i) cin>>a[i],e[i].push_back(a[i]); if(k==1){ for(int i=1;i<=n;++i){ if(a[i]!=i){ cout<<"NO"<<endl;return; } } cout<<"YES"<<endl; } else{ for(int i=1;i<=n;++i){ if(a[i]==i){ cout<<"NO"<<endl;return; } } for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;++i){ if(num[color[i]]!=k&&num[color[i]]!=1){ cout<<"NO"<<endl;return; } } cout<<"YES"<<endl; } } signed main(){ int T=1; cin>>T; init(); while(T--) solve(); return 0; }
标签:缩点,tarjan,int,top,++,low,删点,sum From: https://www.cnblogs.com/buleeyes/p/17789943.html