Loading web-font TeX/Math/Italic


UOJ#266. 【清华集训2016】Alice和Bob又在玩游戏 博弈,DSU on Tree,Trie

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ266.html

题解

首先我们可以直接暴力 O(n2) 用 sg 函数来算答案。

对于一个树就是枚举一下从根出发到哪一个节点为止的路径被删掉了,剩下所有的子树的sg值xor起来,对于每一个路径后的答案取一个 mex 。

我们考虑快速的做这个过程。

直接写个 Trie 再 DSU on tree 就好了,只要支持查询 mex 和整棵 trie 对某一个值 xor 这两种操作就好了。

时间复杂度 O(nlog2n)

P.S. 可以用线段树合并优化复杂度。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#pragma GCC optimize("Ofast","inline")
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
#define outval(x) printf(#x" = %d\n",x)
#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
#define outtag(x) puts("----------"#x"----------")
#define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\
                        For(_v2,L,R)printf("%d ",a[_v2]);puts("");
using namespace std;
typedef long long LL;
LL read(){
    LL x=0,f=0;
    char ch=getchar();
    while (!isdigit(ch))
        f|=ch=='-',ch=getchar();
    while (isdigit(ch))
        x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return f?-x:x;
}
const int N=100005;
namespace Trie{
    const int S=N*20*20;
    int son[S][2],size[S],c=0;
    #define ls son[x][0]
    #define rs son[x][1]
    void Init(){
        while (c)
            clr(son[c]),size[c]=0,c--;
    }
    void Ins(int &x,int d,int v,int tag){
        if (!x)
            x=++c,size[x]=1;
        if (d<0)
            return;
        Ins(son[x][(v^tag)>>d&1],d-1,v,tag);
        size[x]=size[ls]+size[rs];
    }
    void Get(int x,int d,int v,int tag,vector <int> &vec){
        if (!x)
            return;
        if (d<0)
            return vec.pb(v);
        Get(son[x][tag>>d&1],d-1,v,tag,vec);
        Get(son[x][~tag>>d&1],d-1,v|(1<<d),tag,vec);
    }
    int Ask(int x,int d,int v,int tag){
        if (d<0)
            return v;
        if (size[son[x][tag>>d&1]]<(1<<d))
            return Ask(son[x][tag>>d&1],d-1,v,tag);
        else
            return Ask(son[x][~tag>>d&1],d-1,v|(1<<d),tag);
    }
    #undef ls
    #undef rs
}
int n,m;
vector <int> e[N];
struct trie{
    int rt,tag;
}t[N];
int cnt;
int size[N],son[N],sg[N],id[N];
void dfs(int x,int pre){
    size[x]=1,son[x]=0;
    for (auto y : e[x])
        if (y!=pre){
            dfs(y,x);
            size[x]+=size[y];
            if (!son[x]||size[son[x]]<size[y])
                son[x]=y;
        }
}
vector <int> gid;
void dfs2(int x,int pre){
    sg[x]=0;
    int s=0;
    for (auto y : e[x])
        if (y!=pre){
            dfs2(y,x);
            s^=sg[y];
        }
    if (!son[x])
        id[x]=++cnt,t[cnt].rt=t[cnt].tag=0;
    else
        t[id[x]=id[son[x]]].tag^=s^sg[son[x]];
    trie &now=t[id[x]];
    Trie::Ins(now.rt,17,s,now.tag);
    for (auto y : e[x])
        if (y!=pre&&y!=son[x]){
            gid.clear();
            Trie::Get(t[id[y]].rt,17,0,t[id[y]].tag,gid);
            for (auto v : gid)
                Trie::Ins(now.rt,17,v^(s^sg[y]),now.tag);
        }
    sg[x]=Trie::Ask(now.rt,17,0,now.tag);
}
void Main(){
    n=read(),m=read();
    For(i,0,n)
        e[i].clear(),size[i]=0;
    For(i,1,m){
        int x=read(),y=read();
        e[x].pb(y),e[y].pb(x);
    }
    cnt=0;
    int ans=0;
    Trie::Init();
    For(i,1,n)
        if (!size[i]){
            dfs(i,0);
            dfs2(i,0);
            ans^=sg[i];
        }
    puts(ans?"Alice":"Bob");
}
int main(){
    int T=read();
    while (T--)
        Main();
    return 0;
}

  

posted @   zzd233  阅读(441)  评论(2编辑  收藏  举报
编辑推荐:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
阅读排行:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!

点击右上角即可分享
微信分享提示