简化题意:
题意:有一个弱联通的有向图,含有\(?\)个结点和\(?\)条边。试问是否存在方案,赋给每个结点一个自然数权值\(???_?\),满足对于所有结点\(?\),\(???_?=mex\{???_?|(?,?)\in ?\}\)。一个集合的\(mex\)是没有在这个集合中出现的最小自然数。
显然是个基环树,先考虑在树上的情况。
对于一棵树,完全可以将其叶子的值赋为\(0\),然后再顺次向上做即可,一定存在这样的方案。
在基环树上,最后会化为一个环,每个点有权值,所以我们只要考虑环上的不满足情况即可。
考虑两个在环上相邻的节点\(?\rightarrow ?\),设它们的\(val_u\)和\(val_v\)
\(val_?>val_v\),那么不需要修改权值。
- \(val_?=val_?\),那么把\(val_u\)变成\(val_u+1\)
\(val_u<val_?\),那么不需要修改权值。
综上,当且仅当环上点权相同且点数为奇数时不存在方案(因为\(+1\)时会死循环)
值得注意的是,对于一个点要先跑完所有子树再将子节点权值加入桶中,计算\(mex\)。不然会在某个子树中出现其他子树的答案。。。
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int f=1,w=0;char x=0;
while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
return w*f;
}
const int N=200010;
const int INF=1e18;
int num_edge,n,Cnt;
int Cir[N],Vis[N],Val[N];
int head[N<<1],fa[N],Jud[N];
struct Edge{int next,to;} edge[N<<1];
inline void Add(int from,int to)
{
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
head[from]=num_edge;
}
inline void Dfs(int pos)
{
for(int i=head[pos];i;i=edge[i].next)
if(!Cir[edge[i].to]) Dfs(edge[i].to);
for(int i=head[pos];i;i=edge[i].next)
if(!Cir[edge[i].to]) Jud[Val[edge[i].to]]=1;
for(;Jud[Val[pos]];Val[pos]++);
for(int i=head[pos];i;i=edge[i].next)
if(!Cir[edge[i].to]) Jud[Val[edge[i].to]]=0;
}
main(){
int pos=1;n=read();
for(int i=1;i<=n;i++) fa[i]=read(),Add(fa[i],i);
for(;!Vis[pos];pos=fa[pos]) Vis[pos]=1;
for(;!Cir[pos];pos=fa[pos]) Cir[pos]=1;
int Max=-1,Min=INF;
for(int i=1;i<=n;i++)
if(Cir[i]) Cnt++,Dfs(i),Max=max(Max,Val[i]),Min=min(Min,Val[i]);
if(Max==Min&&Cnt&1) puts("IMPOSSIBLE");
else puts("POSSIBLE");
}