BZOJ2115 Xor
题目描述:
题目大意:
给定一张 n 个点 m 条边的无向带权连通图,求一条从点 1 到点 n 的路径,使得经过的边权异或和最大。
路径可以经过重复点和重复边,当一条边被重复经过时也会相应地被 xor 多次。
solution
显然(然而我不会严格证明QAQ),答案是由一条 1 到 n 的路径和若干基本环构成的。
先做一个 序,此处定义所有由 中儿子连向父亲的边称为返祖边。
则每一条返祖边会产生一个基本环。
先选择一条1->n的路径,再从所有基本环里选择若干凑出最大异或和即可。
显然可以用线性基维护所有基本环的值。
So easy!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=200005;
struct enode{int to; ll c;};
bool vis[MAXN];
int num=0,n,m;
ll s[MAXN],g[MAXN];
vector<enode> e[MAXN];
ll read()
{
ll f=1,x=0; char c=getchar();
while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
return x*f;
}
void dfs(int x,int father)
{
//cout<<x<<" "<<s[x]<<endl;
vis[x]=1;
for (int i=0;i<e[x].size();i++)
if (!vis[e[x][i].to])
{
s[e[x][i].to]=s[x]^e[x][i].c;
dfs(e[x][i].to,x);
}
else if (e[x][i].to!=father) g[++num]=s[x]^s[e[x][i].to]^e[x][i].c;
}
struct Xor_Basis
{
int maxsz;
ll basis[65];
void init(){ memset(basis,0,sizeof basis); maxsz=63; }
bool insert(ll x)
{
for (int i=maxsz;i>=0;i--)
if ((x>>i)&1)
if (basis[i]) x^=basis[i];
else { basis[i]=x; break; }
return x;
}
} QAQ;
int main()
{
QAQ.init();
n=read(),m=read();
for (int i=1;i<=m;i++)
{
int u=read(),v=read();ll c=read();
e[u].push_back((enode){v,c});
e[v].push_back((enode){u,c});
}
dfs(1,0);
for (int i=1;i<=num;i++) QAQ.insert(g[i]);
ll ans=s[n];
for (int i=QAQ.maxsz;i>=0;i--) if (!((ans>>i)&1)) ans^=QAQ.basis[i];
printf("%lld\n",ans);
return 0;
}
代码较丑,不喜勿喷。