您的位置:首页 > 其它

bzoj 2115: [Wc2011] Xor(DFS+线性基)

2017-11-28 15:56 253 查看

2115: [Wc2011] Xor

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 3853  Solved: 1609

[Submit][Status][Discuss]

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

思路:

先初始化ans = 任意一条1到n路径的异或和

之后DFS找出所有的环,并存下它们的异或和

将所有环的异或和加入线性基,之后贪心就行了,线性基内元素从大到小扫,如果ans异或后更大,那么就异或

最后就是答案

证明:

①如果环没有任意一个点在你那条初始路径上:

你可以专门走到那个环绕一圈后再原路返回,这样就相当于答案异或了那条环上的权值

②如果有一条1到n的路径比你选的这条更优

很显然这条更优的路径和你一开始选的路径构成了一个环,你走一遍这个环就相当于你原本的那条路径没有走过而走的是更优的那条了

③没有三了

#include<stdio.h>
#include<vector>
using namespace std;
#define LL long long
typedef struct
{
int y;
LL val;
}Road;
Road now;
vector<Road> G[100005];
int cnt, vis[100005];
LL sc[100005], a[300005], p[66];
void Sech(int u)
{
int i;
LL val;
vis[u] = 1;
for(i=0;i<G[u].size();i++)
{
now = G[u][i];
val = sc[u]^now.val;
if(vis[now.y]==1)
a[++cnt] = val^sc[now.y];
else
{
sc[now.y] = val;
Sech(now.y);
}
}
}
int main(void)
{
LL ans, val;
int n, m, i, j, x, y;
scanf("%d%d", &n, &m);
for(i=1;i<=m;i++)
{
scanf("%d%d%lld", &x, &y, &val);
now.y = y, now.val = val;
G[x].push_back(now);
now.y = x;
G[y].push_back(now);
}
sc[1] = 0;
vis[1] = 1;
Sech(1);
ans = sc
;
for(i=1;i<=cnt;i++)
{
for(j=62;j>=0;j--)
{
if(a[i]&(1ll<<j))
{
if(p[j]==0)
{
p[j] = a[i];
break;
}
else
a[i] ^= p[j];
}
}
}
for(i=62;i>=0;i--)
{
if((ans^p[i])>ans)
ans = ans^p[i];
}
printf("%lld\n", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: