zoukankan      html  css  js  c++  java
  • BZOJ 2115 Xor(线性基)

    题意:给定一个n<=50000个点m<=100000条边的无向联通图,每条边上有一个权值wi<=1e18。请你求一条从1到n的路径,使得路径上的边的异或和最大.

    任意一条1到n的路径的异或和,都可以由任意一条1到n路径的异或和与图中的一些环的异或和来组合得到。

    为什么?假如我们已经有一条1到n的路径,考虑在出发之前,先走到图中任意一个环上面,走一遍这个环,然后原路返回,这样我们既得到了这个环的异或值(走到环的路径被走过了 2 次,抵消了),也返回了点1。我们可以对任意的环这样做,从而获得这个环的异或值。有了这个性质,不难验证上述结论是正确的。

    现在的解题思路就非常明确了,首先找出所有的环(利用 DFS 树中的返祖边来找环),然后找一条任意的1到n的路径,其异或值为ans。则我们就需要选择若干个环,使得这些这些环上的异或值与ans异或起来最大。这就转化为线性基的问题了。

    求出所有环的异或值的线性基,由于线性基的良好性质,只需要从大到小考虑选择每个线性基向量能否使得异或值更大即可,容易用贪心证明正确性。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    int Scan() {
        int res=0, flag=0;
        char ch;
        if((ch=getchar())=='-') flag=1;
        else if(ch>='0'&&ch<='9') res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
        return flag?-res:res;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=50005;
    //Code begin...
    
    struct Edge{int p, next; LL w;}edge[N<<2];
    int head[N], cnt=1, vis[N], num;
    LL p[63], node[N], a[N*5];
    
    void add_edge(int u, int v, LL w)
    {
        edge[cnt].p=v; edge[cnt].next=head[u]; edge[cnt].w=w; head[u]=cnt++;
    }
    void dfs(int x, int fa)
    {
        vis[x]=1;
        for (int i=head[x]; i; i=edge[i].next) {
            int v=edge[i].p;
            if (v==fa) continue;
            if (vis[v]) a[++num]=node[v]^node[x]^edge[i].w;
            else node[v]=node[x]^edge[i].w, dfs(v,x);
        }
    }
    void sol()
    {
        FOR(i,1,num) {
            for (int j=62; j>=0; --j) {
                if (!(a[i]>>j)) continue;
                if (!p[j]){p[j]=a[i]; break;}
                a[i]^=p[j];
            }
        }
    }
    int main ()
    {
        int n, m, u, v;
        LL w;
        scanf("%d%d",&n,&m);
        while (m--) scanf("%d%d%lld",&u,&v,&w), add_edge(u,v,w), add_edge(v,u,w);
        dfs(1,0);
        sol();
        LL ans=node[n];
        for (int i=62; i>=0; --i) if ((ans^p[i])>ans) ans^=p[i];
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    NX二次开发-UFUN计时函数UF_end_timer
    NX二次开发-UFUN写入本地文本文档uc4524
    NX二次开发-UFUN关闭本地文本文档uc4540
    NX二次开发-UFUN读取本地文本文档uc4514a
    MFC弹出选择文件和选择文件夹代码
    NX二次开发-UFUN多选菜单对话框uc1605
    NX二次开发-UFUN文件选择对话框UF_UI_create_filebox
    NX二次开发-UFUN多按钮模态对话框UF_UI_message_dialog
    NX二次开发-算法篇-找相切面
    NX二次开发-UFUN获取边的光顺性UF_MODL_ask_edge_smoothness(找相切面)
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6374844.html
Copyright © 2011-2022 走看看