【BZOJ2115】[Wc2011] Xor 高斯消元求线性基+DFS
【BZOJ2115】[Wc2011] Xor
Description

Input
第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目。 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边。 图中可能有重边或自环。
Output
仅包含一个整数,表示最大的XOR和(十进制结果),注意输出后加换行回车。
Sample Input
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2
Sample Output
HINT

题解:以前用到DFS树的情况比较少,现在需要在加深一下对DFS树的理解了~
*结论:任意一条从1到n的路径,都可以被任意令一条从1到n的路径和一堆环替代。(因为是异或,所以显然)
所以我们只需要任意找一条从1到n的路径,然后再把所有的环都找出来。
但是我们这里的环不是Tarjan那里的环,我们要找到的都是简单环,所以要用DFS(有什么区别?)
因为DFS树(就是DFS找出的树)有一个性质:没有横叉边,所以每条返祖边都唯一对应一个简单环。
那么现在问题就变成了给出一堆数,可以选或不选,要求选出来的数和一个固定的数的异或和最大。
方法:网上大部分题解都说先搞出线性基,然后贪心就行了,然而本蒟蒻不知道什么是线性基,现去学了一发
高斯消元的过程,就是我们将一个满秩的矩阵尽可能的消成一个上三角矩阵的过程,而我对线性基的理解就是:最后得到的那个近似于上三角的矩阵(因为有的位置可能没有消完)。容易发现,线性基可以表示原集合中的所有数。
所以你已经知道了一个上三角矩阵,然后如何使得异或值最大呢?显然从大到小一个一个试就行了嘛!如果当前位线性基不为0,但是原数为0,那就异或上这个数就行了。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
int n,m,cnt,tot;
int to[200010],next[200010],head[50010],vis[50010];
ll val[200010],v[500010],dis[50010],ans;
void add(int a,int b,ll c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x,int fa)
{
vis[x]=1;
for(int i=head[x];i!=-1;i=next[i])
{
if(to[i]==fa) continue;
if(vis[to[i]]) v[++tot]=val[i]^dis[to[i]]^dis[x];
else dis[to[i]]=dis[x]^val[i],dfs(to[i],x);
}
}
void gauss()
{
ll i;
int j,k=0;
for(i=1ll<<60;i;i>>=1)
{
for(k++,j=k;j<=tot;j++) if(v[j]&i)
{
swap(v[j],v[k]);
break;
}
if(!(v[k]&i))
{k--; continue;}
for(j=k+1;j<=tot;j++) if(v[j]&i) v[j]^=v[k];
}
}
int main()
{
scanf("%d%d",&n,&m);
int i,a,b;
ll c;
memset(head,-1,sizeof(head));
for(i=1;i<=m;i++)
{
scanf("%d%d%lld",&a,&b,&c);
add(a,b,c),add(b,a,c);
}
dfs(1,0),gauss();
ans=dis[n];
for(i=1;i<=60&&i<=tot;i++) if((ans^v[i])>ans) ans^=v[i];
printf("%lld",ans);
return 0;
}
【BZOJ2115】[Wc2011] Xor 高斯消元求线性基+DFS的更多相关文章
- 【bzoj4269】再见Xor 高斯消元求线性基
题目描述 给定N个数,你可以在这些数中任意选一些数出来,每个数可以选任意多次,试求出你能选出的数的异或和的最大值和严格次大值. 输入 第一行一个正整数N. 接下来一行N个非负整数. 输出 一行,包含两 ...
- HDU3949/AcWing210 XOR (高斯消元求线性基)
求第k小的异或和,用高斯消元求更简单一些. 1 //用高斯消元求线性基 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define ...
- 【BZOJ2322】[BeiJing2011]梦想封印 高斯消元求线性基+DFS+set
[BZOJ2322][BeiJing2011]梦想封印 Description 渐渐地,Magic Land上的人们对那座岛屿上的各种现象有了深入的了解. 为了分析一种奇特的称为梦想封印(Fantas ...
- 【bzoj2115】[Wc2011] Xor DFS树+高斯消元求线性基
题目描述 输入 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边. 图 ...
- 【bzoj3105】[cqoi2013]新Nim游戏 高斯消元求线性基
题目描述 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴.可以只拿一根,也可以拿走整堆火柴,但不能同时从 ...
- 【bzoj4004】[JLOI2015]装备购买 贪心+高斯消元求线性基
题目描述 脸哥最近在玩一款神奇的游戏,这个游戏里有 n 件装备,每件装备有 m 个属性,用向量zi(aj ,.....,am) 表示 (1 <= i <= n; 1 <= j < ...
- bzoj2115 [Wc2011] Xor——高斯消元 & 异或线性基
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2115 异或两次同一段路径的权值,就相当于没有走这段路径: 由此可以得到启发,对于不同的走法, ...
- BZOJ4269再见Xor——高斯消元解线性基
题目描述 给定N个数,你可以在这些数中任意选一些数出来,每个数可以选任意多次,试求出你能选出的数的异或和的最大值和严格次大值. 输入 第一行一个正整数N. 接下来一行N个非负整数. 输出 一行,包含两 ...
- 【BZOJ2460】[BeiJing2011]元素 贪心+高斯消元求线性基
[BZOJ2460][BeiJing2011]元素 Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔法矿石炼制法杖的技术.那时人们就认识到,一个法 ...
随机推荐
- 如何使用apache的 work模式还是 prefork 模式
注意: 2.4之前版本默认为prefork, 2.4已经变为event模式.三种模式比较: http://www.cnblogs.com/fnng/archive/2012/11/20/2779977 ...
- java学习之输入,输出流
输入流与输出流 1,流的分类:字节流和字符流 区别如下: 1,字节流(8位Unicode)在操作的时候本身是不会用到缓冲区(内存)的byte,是与文件本身直接操作的,而字符流(16位Unicode)在 ...
- zabbix通过snmp监控windows主机
1.开启Windows的snmp功能 2.配置snmp服务 设置snmp服务社区名称及允许的主机,设置完成后重启snmp服务 3.在zabbix server上测试 测试需要使用命令snmpwalk, ...
- App开发者博客之: 包建强 (专注移动app开发)
http://www.cnblogs.com/Jax/p/4912606.html 著有"App研发录" 一书. Android EventBus源码解析 带你深入理解EventB ...
- json-server模拟接口获取mock数据
转载:http://blog.csdn.net/stevennest/article/details/76167343 安装json-server 运行以下命令 cnpm install json-s ...
- 【Javascript 基础】对象
1 创建对象 Javascript 支持对象的概率.有多种方法可以用来创建对象. <!DOCTYPE html> <html lang="en"> < ...
- 《Java设计模式》之调停者模式(Mediator)
调停者模式是对象的行为模式.调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显引用.从而使它们能够较松散地耦合.当这些对象中的某些对象之间的相互作用发生改变时,不会马上影响到其它的一些 ...
- Oracle 重置序列
Oracle将自增sequence重置为初始值1时,若是删除再重建,那么依赖它的函数和存储过程将失效,需要重新编译. 这里利用相反的过程,利用负值步长参数,将递增值改为(sequence.NEXTVA ...
- C/C++中字符串与数字之间的转换
主要有两种方式:C 中能够使用 sprintf 将数字转为字符数组,sscanf 将字符数组转为数字:而在 C++ 中不仅能够使用 C 中的方法,还能够使用 stringstream 实现字符串与数字 ...
- mysql时间操作(时间差和时间戳和时间字符串的互转)
mysql时间操作(时间差和时间戳和时间字符串的互转) 两个时间差: MySQL datediff(date1,date2):两个日期相减 date1 - date2,返回天数. select dat ...