bzoj 2115

线性基好题

首先,如果一条路径被经过了两次,那么这条路径上的权值等于没有(废话)

基于这一点,我们其实已经找到了解决问题的方法了!

首先,由于可以反复经过一条边,因此我们可以把一条合法的路径看成这样的结构:

从$1$到$n$有一条链,这条链上挂着一些环,答案是链的贡献异或环的贡献(因为从链到环的边一定会被经过两次,因此不产生贡献)

那么我们只需最大化这个东西就可以了

进一步分析,从$1$到$n$会有很多条链,选哪条呢?

随便选!

因为我们看到,可以从一条链换成另一条链的条件是这两条链各有一部分在同一个环里!

而一条链的一部分异或大环的贡献就相当于切换到了另一条链上,因此我们只需把所有环的贡献扔到一个线性基里,然后找出一条从1到n的路径在这个线性基里查最大贡献即可

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
using namespace std;
struct Edge
{
    int nxt,to;
    ll val;
}edge[200005];
int head[50005];
bool vis[50005];
ll v[50005];
ll p[65];
int n,m;
int cnt=1;
void add(int l,int r,ll w)
{
    edge[cnt].nxt=head[l];
    edge[cnt].to=r;
    edge[cnt].val=w;
    head[l]=cnt++;
}
void ins(ll x)
{
    for(int i=63;i>=0;i--)
    {
        if(!((1ll<<i)&x))continue;
        else if(p[i])x^=p[i];
        else {p[i]=x;break;}
    }
}
ll query(ll x)
{
    ll ret=x;
    for(int i=63;i>=0;i--)if((ret^p[i])>ret)ret^=p[i];
    return ret;
}
void dfs(int x,ll dis)
{
    v[x]=dis,vis[x]=1;
    for(int i=head[x];i;i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(vis[to])ins(dis^edge[i].val^v[to]);
        else dfs(to,dis^edge[i].val);
    }
}
template <typename T>inline void read(T &x)
{
    T f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x=c*f;
}
int main()
{
    read(n),read(m);
    for(int i=1;i<=m;i++)
    {
        int x,y;ll z;
        read(x),read(y),read(z);
        add(x,y,z),add(y,x,z);
    }
    dfs(1,0);
    printf("%lld\n",query(v[n]));
    return 0;
}

 

posted @ 2019-07-12 09:07  lleozhang  Views(47)  Comments(0Edit  收藏
levels of contents