BZOJ2115 [Wc2011] Xor

开始补冬令营期间做的题目啦~

好吧冬令营ydl大爷在讲台上面讲图的树分解,我们一帮二子在下面讨论这道题,讨论了2个小时2333

进入正题。。。首先我们把图dfs一遍,记录下dfs产生的生成树

我们会发现,所有边分成了两种:树边(生成树上的边)和回边(从某个节点到其祖先的边),并且不存在两棵子树之间有边。

定义回边和其中的树边形成的环叫基本环,则基本环最多有m - n个

然后题解上有一句话"不难发现,答案是由1到n号点的一条树链和几个基本环形成的",我去脑补半天啊!!!这是因为操作是xor,所以来回路径上的边都算了两次刚好抵消掉。

于是题解君就卖了个萌"高斯消元即可"。。。什么鬼。。。然后网上都说是什么线性基,那个也不造是什么。。。

其实就是贪心啦!

因为是xor所以可以拆开来看每一位,每次加入一个数的时候,总是查看当前最高位是0的能否变成1,如果不行,查看当前次高位是0的能否变成1,以此类推。

顺便记录下使得某一位是1的时候的一种方案,就可以直接O(64)的推出下一次能不能让某一位从0变成1了。

 1 /**************************************************************
 2     Problem: 2115
 3     User: rausen
 4     Language: C++
 5     Result: Accepted
 6     Time:328 ms
 7     Memory:11412 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <algorithm>
12  
13 using namespace std;
14 typedef long long ll;
15 const int N = 50005;
16 const int M = N << 2;
17 const int Cnt = 100;
18 const int Maxlen = M * 30;
19  
20 struct edge {
21     int next, to;
22     ll v;
23     edge() {}
24     edge(int _n, int _t, ll _v) : next(_n), to(_t), v(_v) {}
25 } e[M];
26  
27 int n, m, cnt;
28 int first[N];
29 ll f[N], Ans;
30 ll ans[Cnt], from[Cnt];
31 bool vis[N];
32  
33 char buf[Maxlen], *c = buf;
34 int Len;
35  
36 inline ll read() {
37     ll x = 0;
38     while (*c < '0' || '9' < *c) ++c;
39     while ('0' <= *c && *c <= '9')
40         x = x * 10 + *c - '0', ++c;
41     return x;
42 }
43  
44 #define y e[x].to
45 void dfs(int p) {
46     int x;
47     vis[p] = 1;
48     for (x = first[p]; x; x = e[x].next)
49         if (!vis[y]) {
50             f[y] = f[p] ^ e[x].v;
51             dfs(y);
52         }
53 }
54 #undef y
55  
56 void work(int x, int y, ll v) {
57     int i;
58     v = v ^ f[x] ^ f[y];
59     for (i = 1; i <= cnt && v; ++i)
60         if (v & ans[i]) v ^= from[i];
61     if (!v) return;
62     ++cnt, ans[cnt] = 1, from[cnt] = v;
63     while ((ans[cnt] << 1) <= v) ans[cnt] <<= 1;
64     for (i = cnt; i > 1; --i)
65         if (ans[i] > ans[i - 1])
66             swap(ans[i], ans[i - 1]), swap(from[i], from[i - 1]);
67 }
68  
69 int main() {
70     Len = fread(c, 1, Maxlen, stdin);
71     buf[Len] = '';
72     int i, x, y;
73     ll z;
74     n = read(), m = read();
75     for (i = 1; i <= m; ++i) {
76         x = read(), y = read(), z = read();
77         e[i] = edge(first[x], y, z), first[x] = i;
78         e[i + m] = edge(first[y], x, z), first[y] = i + m;
79     }
80     dfs(1);
81     for (i = 1; i <= m; ++i)
82         work(e[i].to, e[i + m].to, e[i].v);
83     Ans = f[n];
84     for (i = 1; i <= cnt; ++i)
85         if (!(Ans & ans[i])) Ans ^= from[i];
86     printf("%lld
", Ans);
87     return 0;
88 }
View Code

 (p.s. 写了究极读入优化就变成了rank.1了啊哈哈哈哈哈)

By Xs酱~ 转载请说明 博客地址:http://www.cnblogs.com/rausen
原文地址:https://www.cnblogs.com/rausen/p/4292257.html