BZOJ2115: [Wc2011] Xor(异或方程组)

来源:互联网 发布:卡尔曼滤波c语言 编辑:程序博客网 时间:2024/05/22 07:42

传送门

题意:
求S到T的最大异或路径和。(n5e4,m1e5)

题解:
建议先去啃一啃莫队的课件:https://wenku.baidu.com/view/af57af62ddccda38376baf72.html

首先可以知道的是,我们可以任意选择一棵生成树,对于每一条非树边加入树中形成的环记录下来,由Tarjan 算法过程可知简单环(返祖边)的条数是O(m)的。
那么任意的一条无向图的路径可由这些简单环异或再异或原树中的路径而来(画画图就懂了,注意是简单环)。

问题转化为一堆数选择其中一些来异或,最后再异或k使得值最大。朴素的想法是n2m暴力高斯消元高低位贪心解异或方程组,但是数据范围太大,这时候就要用莫队所说的解法3了。

考虑将系数矩阵转置,那么新的矩阵每一行为原来的数,考虑高斯消元找出这些数的线性基(一共只有63位,那么线性基只会小等于63个),复杂度是O(nlogn)的。

现在考虑这些线性基的含义:每一个主元表示这个基可以任意切换主元这一位的值(前面的值已经确定,后面主元的位置全为0),那么直接高低位贪心就可以做了。

#include<bits/stdc++.h>typedef long long ll;using namespace std;inline ll read(){    char ch=getchar();ll i=0,f=1;    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}    return i*f;}const int LIM=62;const int Maxn=2e5+50;int n,m,g[Maxn],v[Maxn],nt[Maxn],ec,tot,dfn[Maxn],ind,p[100];ll w[Maxn],a[Maxn],h[Maxn];inline void add(int x,int y,ll z){nt[++ec]=g[x];g[x]=ec;v[ec]=y;w[ec]=z;} inline void dfs(int x,int f,ll d){    dfn[x]=++ind;h[x]=h[f]^d;    for(int i=g[x];i;i=nt[i]){        if(!dfn[v[i]])dfs(v[i],x,w[i]);        else if(v[i]!=f&&dfn[v[i]]<dfn[x])a[++tot]=h[x]^h[v[i]]^w[i];    }}inline void solve(ll k){    int t=0;    for(int i=62;i>=0;i--){        for(int j=t+1;j<=n;j++)if(a[j]&(1ll<<i)){swap(a[t+1],a[j]);p[++t]=i;break;}        if(p[t]!=i)continue;        for(int j=t+1;j<=n;j++)if(a[j]&(1ll<<i))a[j]^=a[t];    }    for(int i=1;i<=t;i++){if(!((k>>p[i])&1))k^=a[i];}    printf("%lld\n",k);}int main(){    n=read(),m=read();    for(int i=1;i<=m;i++){        int x=read(),y=read();ll z=read();        add(x,y,z),add(y,x,z);    }     dfs(1,0,0);solve(h[n]); } 
原创粉丝点击