題目
對於 30%的數據, n ≤ 100 ;
對於 40%的數據, n ≤ 1,000 ;
對於 50%的數據, n ≤ 10 ,000 ,且樹是隨機生成的;
對於 100%的數據, 1 ≤ n ≤ 200 ,000 ,且對於節點 i(i ≠ 1),其父節點的編號小於 i。
題意
這題的題意比較坑,不容易理解。
其實就是給你一棵樹,然後黑白染色。
染完色後,設最少需要染x個黑色點可以使得必勝,那麼這k個點便是最小黑方勝集合。
同理可以求出最小白方勝集合。並且這些點有可能有很多種情況
求出所有同是最小黑方勝集合和最小白方勝集合的交集的數目,最小編號,異或值
一個根要求勝的條件是:
若要求黑勝,則
這個點當前是黑色,則只要求它的子樹的任意一個點爲必勝即可。
這個點當前是白色,則要求它的子樹的每一個點都必須是必勝
白色類似
分析
我們可以這樣想,用f[i,j]表示當前根爲i時要求顏色j勝的最少需要確定的葉子節點的個數
轉移明顯,若i顏色和j不同,則
若顏色相同,則
葉子的點則是f[k,0]=f[k,1]=1;
然而我們考慮如何去算子集。
其實也很簡單,我們也是按照dp這樣去做,去選擇,
若當前顏色與j顏色不同,則遞歸每個它的兒子。
若一樣,則選最小的去遞歸,若有相同,則都遞歸即可。
這樣便可以很好解決問題了。
當然,留給讀者思考,若是分別求根的黑,白勝的方案,怎麼辦?
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#define maxlongint 2147483647
using namespace std;
const int N=200100;
int nu,n,b[N],las[N],nex[N],x,color[N],f[N][2];
bool bz[N][2];
void insert(int x,int y){
b[++nu]=y;nex[nu]=las[x];las[x]=nu;
}
void dfs(int x){
if (!las[x]) f[x][0]=f[x][1]=1;
for(int p=las[x];p;p=nex[p]){
color[b[p]]=color[x]^1;
dfs(b[p]);
}
}
void dfe(int x,int y){
if (y==color[x]&&f[x][y]==0) f[x][y]=maxlongint;
for(int p=las[x];p;p=nex[p]){
dfe(b[p],y);
if (y==color[x]) f[x][y]=min(f[x][y],f[b[p]][y]);
else f[x][y]=f[x][y]+f[b[p]][y];
}
}
void dfan(int x,int y){
int pe=maxlongint;
for(int p=las[x];p;p=nex[p]){
if (y==color[x]) {
if (pe>f[b[p]][y])pe=f[b[p]][y];
}else dfan(b[p],y);
}
if (y==color[x]&&las[x]) for(int p=las[x];p;p=nex[p])
if (f[b[p]][y]==pe) dfan(b[p],y);
if (!las[x]) bz[x][y]=1;
}
int main(){
scanf("%d",&n);
for(int i=2;i<=n;i++) {
scanf("%d",&x);
insert(x,i);
}
color[1]=1;
dfs(1);
dfe(1,1);
dfe(1,0);
dfan(1,1);
dfan(1,0);
int an=0,ans=0,mi=maxlongint;
for(int i=1;i<=n;i++){
if (bz[i][1]&&bz[i][0]) {
an++;mi=min(mi,i);ans=ans^i;
}
}
printf("%d %d %d",mi,an,ans);
}