[arc079f]namori grundy

题意:

给出一个基环外向树,每个点有一个$sg$值为所有子节点的$mex$值,求是否有设置$sg$值的方案满足条件。

题解:

感觉没有B题难。。。听完讲评就会了。。。

这题栋爷有一种拆环的做法,但是我写的是讲题的时候ckw讲的一种神仙做法,个人感觉容易理解一点qwq

如果觉得ckw的博客过于神仙可以看看hy写的题解,讲的很清楚qwq(我太垃圾了)

对了此题还有lzx的一种神仙做法qwq(我太太太垃圾了)

首先如果是一棵树,显然必定有解,所有叶节点设0,然后取mex即可;

考虑拓展到基环外向树上,这个树的结构是一个环上的节点和各自的子树构成,那么不妨先对每个子树求出各自的$sg$值(必定有解),然后把环扒出来单独看;

此时环上的每个节点都有了一个初始的$sg$值,不难发现这个值就是解的下界,现在要做的就是在下界上构造出满足题目要求的解;

考虑两个在环上相邻的节点$u\rightarrow v$,设它们的$sg$值分别为$sg_u$和$sg_v$,分三类考虑:

1.若$sg_u>sg_v$,那么不用做任何改动,因为$sg_v$已经被包含在$u$的子节点$sg$中了;

2.若$sg_u=sg_v$,那么把$sg_u$变成$sg_u+1$即可;

3.若$sg_u<sg_v$,也不需要任何改动。。。因为$sg_v$并不在$sg_u$的范围内;

所以可以发现两个点只要相等就可以通过+1来调整,只要不等就不需要再调整,所以肯定会有解;

那么无解情况是什么呢?考虑所有初始值都相等的情况,此时我们需要对隔一个点加一来使得每对相邻点都不相等,环长度为偶数时正好加完,但是当环的长度为奇数的时候加完一圈回去奇偶性就改变了,所以要一直无限的加下去,明显这就是无解的情况。

暴力dfs模拟上述过程即可

代码:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 using namespace std;
 7 struct edge{
 8     int v,next;
 9 }a[200001];
10 int n,now,maxn=-2147483647,minn=2147483647,bcc=0,tot=0,sg[200001],head[200001],p[200001];
11 bool used[200001],huan[200001];
12 void add(int u,int v){
13     a[++tot].v=v;
14     a[tot].next=head[u];
15     head[u]=tot;
16 }
17 void dfs(int u){
18     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
19         int v=a[tmp].v;
20         if(!huan[v])dfs(v);
21     }
22     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
23         int v=a[tmp].v;
24         if(!huan[v])used[sg[v]]=true;
25     }
26     for(;used[sg[u]];sg[u]++);
27     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
28         int v=a[tmp].v;
29         if(!huan[v])used[sg[v]]=false;
30     }
31 }
32 int main(){
33     memset(head,-1,sizeof(head));
34     memset(sg,0,sizeof(sg));
35     scanf("%d",&n);
36     for(int i=1;i<=n;i++){
37         scanf("%d",&p[i]);
38         add(p[i],i);
39     }
40     now=1;
41     for(;!used[now];now=p[now])used[now]=1;
42     for(;!huan[now];now=p[now])huan[now]=1;
43     memset(used,0,sizeof(used));
44     for(int i=1;i<=n;i++){
45         if(huan[i]){
46             dfs(i);
47             bcc++;
48             maxn=max(maxn,sg[i]);
49             minn=min(minn,sg[i]);
50         }
51     }
52     if(maxn==minn&&bcc%2)printf("IMPOSSIBLE");
53     else printf("POSSIBLE");
54     return 0;
55 }

 

posted @ 2018-08-22 22:55  DCDCBigBig  阅读(208)  评论(0编辑  收藏  举报