开始补冬令营期间做的题目啦~
好吧冬令营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] = '\0'; 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\n", Ans); 87 return 0; 88 }
(p.s. 写了究极读入优化就变成了rank.1了啊哈哈哈哈哈)
By Xs酱~ 转载请说明
博客地址:http://www.cnblogs.com/rausen