Atcoder agc35c(5140) Skolem XOR Tree 题解

题意简述

给定一个$n<=1e5$,构造一颗$2n$个节点的数。其中,点$i$和$i+n$上都带点权$i$,并且满足:
对于$1<=i<=n$,$i$到$i+n$的路径上(包括两端点),所有点权的异或和为$i$。

举例:
i=3,构造图如下:

其中,4,5,6的点权分别是1,2,3。不难验证,满足题设条件。

如果无解,输出No。

思路

当且仅当$n=2^x$时,无解。(x为自然数

先构造一个上面样例的图。

然后,如这个图所示:

如果$n$是奇数,就把$(4,5)$,$6,7$,$8,9$…$(n-1,n)$都按这样的构造,连接到点$1+n$上就珂以了。
如果$n$是偶数,先把前$n-1$个点按照这样的方式构造一颗树。然后考虑$n$和$2n$。找到比$n$小的最大的$2$的幂$p$,显然,$p->1->(n^p^1)$,这条路径的异或和为$n$。并且,这条路径存在(已证)。那么,我们把$n$链接到$p$上,把$2n$链接到$n^p^1$上,即珂。

代码

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

#include <bits/stdc++.h>using namespace std;
namespace Flandre_Scarlet
{
#define N 155555
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define p_b push_back
#define sz(a) ((int)a.size())
#define iter(a,p) (a.begin()+p)
void R1(int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=(f==1)?x:-x;
}
void Rd(int cnt,...)
{
va_list args;
va_start(args,cnt);
F(i,1,cnt)
{
int* x=va_arg(args,int*);R1(*x);
}
va_end(args);
}

int n;
void Input()
{
R1(n);
}
void Add(int u,int v){printf("%d %d\n",u,v);}
void Soviet()
{
F(i,0,20) if ((1<<i)==n)
{
puts("No");return;
}
puts("Yes");
Add(1,2);
Add(2,3);
Add(3,n+1);
Add(n+1,n+2);
Add(n+2,n+3);
Fs(i,5,n,i+=2)
{
Add(1+n,i);
Add(i,i-1);
Add(1+n,i-1+n);
Add(i-1+n,i+n);
}
if (n%2==0)
{
int p2;
F(i,0,20) if ((1<<i)<n) p2=(1<<i);

Add(n,p2+n);
Add(2*n,n^p2^1);
}


}

#define Flan void
Flan IsMyWife()
{
Input();
Soviet();
}
}
int main(){
Flandre_Scarlet::IsMyWife();
return 0;
}
w