Trie树维护Sg值,类似线段树合并的方式合并子树,复杂度 O(nlog(n))
/**************************************************************
Problem: 4134
User: Clare
Language: C++
Result: Accepted
Time:1988 ms
Memory:73476 kb
****************************************************************/
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 100010
int n,m;
int A[N],f[N],h[N],C[40],root[N];
struct Edge{
int to,next;
}edge[N*2];
int head[N],Tot;
struct Node{
int l,r,flag;
bool Full,Be_ans;
}t[N*40];
int tot;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void Addedge(int u,int v)
{
Tot++;edge[Tot].next=head[u];edge[Tot].to=v;head[u]=Tot;
Tot++;edge[Tot].next=head[v];edge[Tot].to=u;head[v]=Tot;
}
void Rev(int Floor,int k,int x)
{
if(!x||Floor<0)
return;
t[x].flag^=k;
if(k&C[Floor])
swap(t[x].l,t[x].r);
}
void Pushdown(int Floor,int x)
{
if(t[x].flag)
{
Rev(Floor-1,t[x].flag,t[x].l);
Rev(Floor-1,t[x].flag,t[x].r);
t[x].flag=0;
}
}
int Build(int Floor,int k)
{
int now=++tot;
if(Floor<0)
{
t[now].Full=1;
return now;
}
if(k&C[Floor])
t[now].r=Build(Floor-1,k);
else t[now].l=Build(Floor-1,k);
return now;
}
int Merge(int Floor,int k,int x,int y)
{
if(!y)
return x;
if(!x)
{
Rev(Floor,k,y);
return y;
}
int now=++tot;
if(Floor<0)
{
t[now].Full=1;
return now;
}
Pushdown(Floor,x);Pushdown(Floor,y);
if(k&C[Floor])
{
t[now].l=Merge(Floor-1,k,t[x].l,t[y].r);
t[now].r=Merge(Floor-1,k,t[x].r,t[y].l);
}
else
{
t[now].l=Merge(Floor-1,k,t[x].l,t[y].l);
t[now].r=Merge(Floor-1,k,t[x].r,t[y].r);
}
t[now].Full=t[t[now].l].Full&t[t[now].r].Full;
return now;
}
int Mex(int Floor,int x)
{
if(Floor<0)
return 0;
Pushdown(Floor,x);
if(!t[t[x].l].Full)
{
x=t[x].l;
return Mex(Floor-1,x);
}
else
{
x=t[x].r;
return C[Floor]+Mex(Floor-1,x);
}
}
void DFS(int k,int fa)
{
for(int i=head[k];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa)
continue;
DFS(v,k);
h[k]^=f[v];
}
if(!A[k])
root[k]=Build(m,h[k]);
for(int i=head[k];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa)
continue;
root[k]=Merge(m,h[k]^f[v],root[k],root[v]);
}
f[k]=Mex(m,root[k]);
}
void Find(int k,int fa,int ans)
{
ans^=h[k]^f[k];
if(!A[k]&&!ans)
t[k].Be_ans=true;
for(int i=head[k];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa)
continue;
Find(v,k,ans);
}
}
int main()
{
C[0]=1;
for(int i=1;i<=30;i++)
C[i]=C[i-1]<<1;
n=read();
for(int i=1;i<=n;i++)
A[i]=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
Addedge(x,y);
}
while(C[m]<=n)m++;
m--;
DFS(1,0);
if(!f[1])
{
printf("-1\n");
}
else
{
Find(1,0,f[1]);
for(int i=1;i<=n;i++)
{
if(t[i].Be_ans)
printf("%d\n",i);
}
}
return 0;
}