Description
给出一个n个点n条边的有向图,保证每个点出度为1
问能否给每个节点染色,使得每个节点的颜色为所有出边连向点的颜色的mex
Solution
题图就是一个环套树,并且边是向着环的
考虑树的情况,肯定可以染色,并且每个节点的答案c[x]就是我们在树上做mex
考虑环的情况,肯定染成01交替,出现奇环就是IM
可以证明此时的出来的c[]是染色的一个下界
组合在一起就是,当出现了奇环,且每个奇环上的点的颜色都相同,那么肯定不行
证明的话,可以考虑任取颜色全部相同的一个奇环上的点把它改成c[x]+1,然后可以发现是不满足的
如果是偶环的话,我们可以通过修改所有奇数位置。
如果不全相同,考虑一条边(i,j)
若c[i]>c[j],此时不需要修改,因为c[j]已经出现过了
若c[i]<c[j],也不需要修改,因为都是整数,说明c[i]恰好就是mex
若c[i]=c[j],那么就是上面的情况了,我们选一个+1就行
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <stack>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int N=200005;
std:: stack <int> stack;
std:: vector <int> vec;
struct edge {int x,y,next;} e[N*2];
int used[N],dep[N],ls[N],p[N],f[N],d,wjp,edCnt=1;
bool vis[N],in[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
}
void dfs1(int x) {
stack.push(x);
for (int i=ls[x];i;i=e[i].next) {
if (!vis[e[i].y]) {
vis[e[i].y]=1;
dep[e[i].y]=dep[x]+1;
dfs1(e[i].y);
} else {
int y=0;
while (y!=e[i].y) {
y=stack.top(),stack.pop();
vec.push_back(y);
in[y]=1;
}
}
}
}
void dfs2(int x,int from) {
for (int i=ls[x];i;i=e[i].next) {
if (!in[e[i].y]&&e[i].y!=from) dfs2(e[i].y,x);
}
++wjp;
for (int i=ls[x];i;i=e[i].next) {
if (!in[e[i].y]&&e[i].y!=from) {
used[f[e[i].y]]=wjp;
}
}
for (f[x]=0;used[f[x]]==wjp;) f[x]++;
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int n=read(),rec=-1;
rep(i,1,n) p[i]=read();
rep(i,1,n) add_edge(i,p[i]);
dep[1]=vis[1]=1;
dfs1(1);
rep(i,1,n) add_edge(p[i],i);
bool flag=false;
for (int x:vec) {
dfs2(x,0);
if (rec==-1) rec=f[x];
else if (rec!=f[x]) flag=true;
}
if ((vec.size()&1)&&(!flag)) puts("IMPOSSIBLE");
else puts("POSSIBLE");
return 0;
}