您的位置:首页 > 其它

bzoj 2115: [Wc2011] Xor

2018-03-01 19:54 423 查看

Description



Input

第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目。 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边。 图中可能有重边或自环。

Output

仅包含一个整数,表示最大的XOR和(十进制结果),注意输出后加换行回车。

Sample Input

5 7

1 2 2

1 3 2

2 4 1

2 5 1

4 5 3

5 3 4

4 3 2

Sample Output

6

HINT



对于一个环,我们可以从1走到环上,走一圈再原路返回1

这样我们可以只把环的值加到答案里面

那么问题就转换成了,1到n的一条路径和环的值异或求最大值

首先我们先证明任意一条1到n的路径都可以求出最优解

假设当前为路径S1,更优解为路径S2

因为S1和S2不是同一条路径,所以S1与S2一定会形成若干个环

那么S1通过与这些环异或就可以转变成路径S2

因此任取一条路径肯定能够得出最优解

然后环的值该如何求

我们考虑通过dfs求出返祖边,这样能求出一些环,而所有环一定都是这些环的异或组合起来

然后对于如何求出这个最大值,我们考虑构造出我们得到那些环价值的线性基

一开始ans取1到n的路径值,然后对于线性基贪心一下就可以了 

#include<map>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct line
{
int s,t;
long long x;
int next;
}a[200001];
int head[100001];
int edge;
inline void add(int s,int t,long long x)
{
a[edge].next=head[s];
head[s]=edge;
a[edge].s=s;
a[edge].t=t;
a[edge].x=x;
}
int n,cnt,tot;
long long s[1000001];
bool v[100001];
long long dis[100001];
inline void dfs(int d)
{
v[d]=true;
int i;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(!v[t])
{
dis[t]=(dis[d]^a[i].x);
dfs(t);
}
else
{
tot++;
s[tot]=(dis[d]^a[i].x^dis[t]);
}
}
}
//long long a[10001];
long long p[64],d[64];
inline void guass()
{
memset(d,0,sizeof(d));
int i,j;
for(i=1;i<=tot;i++)
{
for(j=63;j>=0;j--)
{
if((s[i]>>j)&1)
{
if(d[j])
s[i]^=d[j];
else
{
d[j]=s[i];
break;
}
}
}
}
}
inline void rebuild()
{
cnt=0;
int i,j;
for(i=63;i>=0;i--)
{
for(j=i-1;j>=0;j--)
{
if((d[i]>>j)&1)
d[i]^=d[j];
}
}
for(i=0;i<63;i++)
if(d[i])
p[cnt++]=d[i];
}
int main()
{
int m;
scanf("%d%d",&n,&m);
int i;
int s,t;
long long x;
for(i=1;i<=m;i++)
{
scanf("%d%d%lld",&s,&t,&x);
edge++;
add(s,t,x);
edge++;
add(t,s,x);
}
dfs(1);
guass();
rebuild();
long long ans=dis
;
for(i=63;i>=0;i--)
if((ans^p[i])>ans)
ans=(ans^p[i]);
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线性基