【bzoj21115 [Wc2011] Xor 带全无向图中1道n经过路径权值的最大异或和(含有环)】

这道题要求从1到n的最大xor和路径,存在重边,允许经过重复点、重复边。

第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目。 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边。 图中可能有重边或自环。

输出:仅包含一个整数,表示最大的XOR和(十进制结果) 

输入

5 7
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2

输出

6
题目要求很清楚,看了大佬的博客,
不过还是自己手写一下思路吧。
可以从1道n随意找一条路径然后求出他的初始的异或和,作为初始值。
然后找到所有的环。。
题解
题解
 

我们考虑如何得到答案,首先所有的环都是可以经过的。这是为什么呢?
一个边权为非负整数的无向连通图,节点编号为1到N,试求出一条从1号节点到N号节点的路径,使得路径上经过的边得权值的XOR和最大.
假设我们从1号点开始走,走到一个环的起点,然后我们经过这个环以后回到了环的起点,这时我们可以直接回到起点。这样,除了环上的路径,其他的路径都被抵消了。

那么我们就只选了了这个环,也就是说,任意一个环都是可以选的。
然后我们先把所有的环都选出来,选入线性基中,再选出任意一条从1到n的路径,作为初始ans。初始ans异或线性基的最大值就是我们求的答案。为什么任意选一条路径也是可行的呢?
我们选了一条路径以后,如果存在一条更优的路径,那么这两条路径肯定是构成一个环的,会被选入线性基中。那么我们再用初始的ans异或一下这个环,我们就会发现,初始的ans被抵消了,二更优的那条路径留了下来。所以,我们选一个任意的初始ans是可行的。
于是这道题的实现就很明显了。先找出所有环,构成线性基,然后找出初始ans。这两步显然是可以dfs一遍一起搞的。然后用ans去异或线性基。从高位开始往低位异或。如果当前ans异或这一位的数能使ans变大,那么就异或。最终得到的ans就是我们要求的答案。

所以根据这题,我们得到一个结论:任意一条1到n的路径的异或和,都可以由任意一条1到n的路径的异或和和一些环的异或和来组合得到。

 

#include
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef pair PII;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int maxn = 1e6 + 5;
using namespace std;
int n,m;
struct Point{
    ll next,to,val;
}edge[maxn*2];
ll head[maxn],cnt;
ll cnn;//成环的个数
ll a[maxn];//线性基
ll A[maxn];//成环的点
ll d[maxn];//环中到i点的异或和
bool vis[maxn];//访问标记
void init(){
    memset(head,0,sizeof(head));
    memset(vis,false,sizeof(0));
    memset(A,0,sizeof(A));
    cnt=0;
    cnn=0;
}
void add(ll u,ll v,ll w)
{
    cnt++;
    edge[cnt].to=v;
    edge[cnt].val=w;
    edge[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int u)
{
    vis[u]=true;
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!vis[v])
        {
            d[v]=d[u]^edge[i].val;
            dfs(v);
        }
        else
            A[cnn++]=d[u]^d[v]^edge[i].val;//环的权值
    }
}
void build(ll p)
{
    for(int i=62;i>=0;--i)
    {
        if(p>>i&1)//if(p&ll(1ll=0;--i)
    {
        if((ans^a[i])>ans)
            ans^=a[i];
    }
    return ans;
}
int main()
{
    ll u,v,w;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=0;i

 

你可能感兴趣的:(ACM,线性基)