bzoj 4134 ljw和lzr的hack比赛

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值