这题在考场上直接写的TreeDP……当时也没想出一个像样的暴力来对拍……好像只能这么直接做了……?

  都说是博弈树了,转移关系都给的这么直接了……也没啥难度了吧= =(怪不得大家都不愿意写题解)

 

  我的思路是这样的:

  如果黑方想赢,那么:

  1.在一个决策方为黑方的节点,对于它来说,最小黑方胜集合就是所有儿子中最小的那个 最小黑方胜集合

  2.在一个决策方为白方的节点,它的最小黑方胜集合是所有儿子的最小黑方胜集合的并

  那么现在我们就可以通过子节点的最小黑方胜集合,推出在某个节点状态下的最小黑方胜集合的大小,然而我们容易发现:哪些元素可能是最小黑方胜集合中的元素,也是满足这个转移的:

  1.对每个节点维护一个mn[x]表示这个最小xx集合的大小,如果mn[son[i]]==mn[fa],就把son的节点集合并入fa的,如果mn[son[i]]<mn[fa],就把fa的节点集合改为son的。

  第二种情况下的话直接并吧……$mn[fa]=\sum mn[son[i]]$

 

同理我们也能找出所有可能在最小白方胜集合中的叶节点……

求个并,随便搞搞出解即可

 

P.S.这题其实求树上某个节点的“最小黑方胜”集合内可能的节点时,求集合的并其实最简单的,拿链表搞搞就可以……但是蒟蒻不会写QAQ(没写过),加上昨天刚好考了一道可并堆的题目,就拿可并堆写了,权当复习……

  1 /**************************************************************
  2     Problem: 3164
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:648 ms
  7     Memory:30304 kb
  8 ****************************************************************/
  9  
 10 //Huce #6 B 
 11 #include<vector>
 12 #include<cstdio>
 13 #include<cstdlib>
 14 #include<cstring>
 15 #include<iostream>
 16 #include<algorithm>
 17 #define rep(i,n) for(int i=0;i<n;++i)
 18 #define F(i,j,n) for(int i=j;i<=n;++i)
 19 #define D(i,j,n) for(int i=j;i>=n;--i)
 20 using namespace std;
 21  
 22 int getint(){
 23     int v=0,sign=1; char ch=getchar();
 24     while(ch<'0'||ch>'9') {if (ch=='-') sign=-1; ch=getchar();}
 25     while(ch>='0'&&ch<='9') {v=v*10+ch-'0'; ch=getchar();}
 26     return v*sign;
 27 }
 28 typedef long long LL;
 29 const int N=400010,INF=~0u>>2;
 30 /*******************tamplate********************/
 31 int hd[N],to[N],ne[N],cnt;
 32 void add(int x,int y){
 33     to[++cnt]=y; ne[cnt]=hd[x]; hd[x]=cnt;
 34 }
 35 struct node{int v,l,r,dis;}t[N];
 36 #define L t[x].l
 37 #define R t[x].r
 38 int n,m,black[N],white[N],rt[N],mn[N],tot,fa[N];
 39  
 40 int merge(int x,int y){
 41     if (!x || !y) return x+y;
 42     if (t[x].v>t[y].v) swap(x,y);
 43     R=merge(R,y);
 44     if (t[L].dis<t[R].dis) swap(L,R);
 45     t[x].dis=t[R].dis+1;
 46     return x;
 47 }
 48 bool sign[N];
 49 void dfs(int x,bool now){
 50     if (!hd[x]){
 51         mn[x]=1;
 52         rt[x]=++tot;
 53         t[tot].v=x;
 54         t[tot].l=t[tot].r=t[tot].dis=0;
 55         return;
 56     }
 57     if (sign[x]==now) mn[x]=INF; else mn[x]=0;
 58     for(int i=hd[x];i;i=ne[i]){
 59         sign[to[i]]=sign[x]^1;
 60         dfs(to[i],now);
 61         if (sign[x]==now){
 62             if (mn[x]>mn[to[i]]){
 63                 mn[x]=mn[to[i]];
 64                 rt[x]=rt[to[i]];
 65             }else if (mn[x]==mn[to[i]]){
 66                 rt[x]=merge(rt[x],rt[to[i]]);
 67             }
 68         }else{
 69             mn[x]+=mn[to[i]];
 70             rt[x]=merge(rt[x],rt[to[i]]);
 71         }
 72     }
 73 }
 74 int ans[N];
 75 int main(){
 76 #ifndef ONLINE_JUDGE
 77     freopen("B.in","r",stdin);
 78 //  freopen("output.txt","w",stdout);
 79 #endif
 80     n=getint();
 81     F(i,2,n){
 82         fa[i]=getint(); add(fa[i],i);
 83     }
 84     tot=0; sign[1]=1;
 85     dfs(1,1);
 86     int num1=0;
 87     while(rt[1]){black[++num1]=t[rt[1]].v; rt[1]=merge(t[rt[1]].l,t[rt[1]].r);}
 88     sort(black+1,black+num1+1);
 89     tot=0; memset(rt,0,sizeof rt);
 90     dfs(1,0);
 91     int num2=0;
 92     while(rt[1]){white[++num2]=t[rt[1]].v; rt[1]=merge(t[rt[1]].l,t[rt[1]].r);}
 93     sort(white+1,white+num2+1);
 94     int num=0;
 95     for(int i=1,j=1;i<=num1 && j<=num2;i++){
 96         while(black[i]>white[j] && j<=num2) j++;
 97         if (black[i]==white[j]) ans[++num]=black[i];
 98     }
 99     int sum=0;
100     F(i,1,num) sum^=ans[i];
101     printf("%d %d %d\n",ans[1],num,sum);
102     return 0;
103 }
104 
View Code

相关文章:

  • 2021-07-19
  • 2021-05-22
  • 2022-02-04
  • 2021-05-20
  • 2021-09-17
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-12-03
  • 2022-02-20
  • 2021-08-25
  • 2021-12-06
  • 2022-12-23
  • 2021-11-03
相关资源
相似解决方案