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;
}
代码较丑,不喜勿喷。