您的位置:首页 > 其它

BZOJ 2115: [Wc2011] Xor

2017-02-03 21:24 357 查看

2115: [Wc2011] Xor

Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 2884 Solved: 1225
[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

HINT



Source

[Submit][Status][Discuss]

本来挺水的一道题,因为一个细节上的long long问题,WA了一晚上。

明天还有WC呢,要睡觉了,/(ㄒoㄒ)/~~

这题乍一看和线性基不沾边哈,但确实是线性基,2333~~~

一个发现——所有路径均可以分为一条从1到n的简单路径+若干个简单环。

所以从原图中随意找一棵生成树,在树上跑DFS求出每个点到根的路径和(异或意义上的)。

然后找出所有的基本环(只包含一条非树边),其环上的异或和为Dis[x]^Dis[y]^Val[i]。

所有的简单环都可以由基本环组成,所以我们就有了所有环——子集异或和。

那么,这不就是线性基的问题吗?求出线性基之后贪心“增广”1到n的路径即可。

#include <bits/stdc++.h>

typedef long long lnt;

const int mxn = 500005;

int n, m;

int hd[mxn];
int to[mxn];
int nt[mxn];
lnt vl[mxn];

inline void addEdge(int u, int v, lnt w)
{
static int tot = 0;

nt[tot] = hd[u];
to[tot] = v;
vl[tot] = w;
hd[u] = tot++;
}

int vis[mxn];
lnt dis[mxn];
lnt cir[mxn];
int tot;

void dfs(int u)
{
vis[u] = true;

for (int i = hd[u], v; ~i; i = nt[i])
if (!vis[v = to[i]])
dis[v] = dis[u] ^ vl[i], dfs(v);
else
cir[++tot] = dis[u] ^ dis[v] ^ vl[i];
}

int cnt;

inline void gauss(void)
{
for (int i = 1; i <= tot; ++i)
{
for (int j = tot; j > i; --j)
if (cir[i] < cir[j])
std::swap(cir[i], cir[j]);

if (cir[i])
++cnt;
else
break;

for (int j = 63; ~j; --j)
if ((cir[i] >> j) & 1)
{
for (int k = 1; k <= tot; ++k)
if (i != k && (cir[k] >> j) & 1)
cir[k] ^= cir[i];

break;
}
}
}

inline void solve(void)
{
lnt ans = dis
;

for (int i = 1; i <= cnt; ++i)
ans = std::max(ans, ans ^ cir[i]);

printf("%lld\n", ans);
}

signed main(void)
{
scanf("%d%d", &n, &m);

memset(hd, -1, sizeof(hd));

for (int i = 1; i <= m; ++i)
{
static int x, y;
static lnt w;

scanf("%d%d%lld", &x, &y, &w);

addEdge(x, y, w);
addEdge(y, x, w);
}

dfs(1);

gauss();

solve();
}


@Author: YouSiki
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: