ARC 079 F Namori Grundy - 结论题 - 基环树

如果给你一棵树那么答案显然是p并且每个点权值固定。
先把所有环上的边断开考虑每个环上的点,求出一个权值。
环边的影响是,如果有x->y,并且a(x)=a(y)那么此时a(x)会变大为a’(x),继而若z->x并且a(z)=a’(x),那么a(z)会变大,依次类推。
显然有影响的边x->y当且仅当a(x)>=a(y),这样就能够把环拆成若干链,不同的链互补影响,并且每一条链都一定可以被改好……是不可能的。因为有可能这条链首尾相接,也就是所有a(x)都想等。此时若环长是奇数那么就会得到imp。
因此结论是如果环上的点之考虑其向外的树得到的mex值a都相等并且环长是奇数那么就是imp,否则答案是p。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
#define N 200010
using namespace std;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int vis[N],f[N],onc[N],a[N];vector<int> g[N];
int dfs(int x)
{
    for(int i=0;i<(int)g[x].size();i++)
        if(!onc[g[x][i]]) dfs(g[x][i]);
    for(int i=0;i<(int)g[x].size();i++)
        if(!onc[g[x][i]]) vis[a[g[x][i]]]=1;
    for(a[x]=0;vis[a[x]];a[x]++);
    for(int i=0;i<(int)g[x].size();i++)
        if(!onc[g[x][i]]) vis[a[g[x][i]]]=0;
    return 0;
}
int main()
{
    int n=inn(),mx=-1,mn=n+1,cnt=0;
    for(int i=1;i<=n;i++)
        f[i]=inn(),g[f[i]].push_back(i);
    int x=1;while(!vis[x]) vis[x]=1,x=f[x];
    memset(vis,0,sizeof(int)*(n+1));
    while(!onc[x]) onc[x]=1,x=f[x];
    for(int i=1;i<=n;i++) if(onc[i])
        dfs(i),mx=max(a[i],mx),mn=min(a[i],mn),cnt++;
//  for(int i=1;i<=n;i++) debug(i)sp,debug(a[i])ln;
    if(mx==mn&&cnt%2==1) return !printf("IMPOSSIBLE\n");
    return !printf("POSSIBLE\n");
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/81945228