• BZOJ 2115: [Wc2011] Xor


    2115: [Wc2011] Xor

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 2884  Solved: 1225
    [Submit][Status][Discuss]

    Description

    Input

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

    Output

    仅包含一个整数,表示最大的XOR和(十进制结果),注意输出后加换行回车。

    Sample Input

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

    Sample Output

    6

    HINT

    Source

     
    [Submit][Status][Discuss]

    本来挺水的一道题,因为一个细节上的long long问题,WA了一晚上。

    明天还有WC呢,要睡觉了,/(ㄒoㄒ)/~~

    这题乍一看和线性基不沾边哈,但确实是线性基,2333~~~

    一个发现——所有路径均可以分为一条从1到n的简单路径+若干个简单环。

    所以从原图中随意找一棵生成树,在树上跑DFS求出每个点到根的路径和(异或意义上的)。

    然后找出所有的基本环(只包含一条非树边),其环上的异或和为Dis[x]^Dis[y]^Val[i]。

    所有的简单环都可以由基本环组成,所以我们就有了所有环——子集异或和。

    那么,这不就是线性基的问题吗?求出线性基之后贪心“增广”1到n的路径即可。

     1 #include <bits/stdc++.h>
     2 
     3 typedef long long lnt;
     4 
     5 const int mxn = 500005;
     6 
     7 int n, m;
     8 
     9 int hd[mxn];
    10 int to[mxn];
    11 int nt[mxn];
    12 lnt vl[mxn];
    13 
    14 inline void addEdge(int u, int v, lnt w)
    15 {
    16     static int tot = 0;
    17     
    18     nt[tot] = hd[u];
    19     to[tot] = v;
    20     vl[tot] = w;
    21     hd[u] = tot++;
    22 }
    23 
    24 int vis[mxn];
    25 lnt dis[mxn];
    26 lnt cir[mxn];
    27 int tot;
    28 
    29 void dfs(int u)
    30 {
    31     vis[u] = true;
    32     
    33     for (int i = hd[u], v; ~i; i = nt[i])
    34         if (!vis[v = to[i]])
    35             dis[v] = dis[u] ^ vl[i], dfs(v);
    36         else
    37             cir[++tot] = dis[u] ^ dis[v] ^ vl[i];
    38 }
    39 
    40 int cnt;
    41 
    42 inline void gauss(void)
    43 {
    44     for (int i = 1; i <= tot; ++i)
    45     {
    46         for (int j = tot; j > i; --j)
    47             if (cir[i] < cir[j])
    48                 std::swap(cir[i], cir[j]);
    49         
    50         if (cir[i])
    51             ++cnt;
    52         else
    53             break;
    54         
    55         for (int j = 63; ~j; --j)
    56             if ((cir[i] >> j) & 1)
    57             {
    58                 for (int k = 1; k <= tot; ++k)
    59                     if (i != k && (cir[k] >> j) & 1)
    60                         cir[k] ^= cir[i];
    61                 
    62                 break;
    63             }
    64     }
    65 }
    66 
    67 inline void solve(void)
    68 {
    69     lnt ans = dis[n];
    70     
    71     for (int i = 1; i <= cnt; ++i)
    72         ans = std::max(ans, ans ^ cir[i]);
    73     
    74     printf("%lld
    ", ans);
    75 }
    76 
    77 signed main(void)
    78 {
    79     scanf("%d%d", &n, &m);
    80     
    81     memset(hd, -1, sizeof(hd));
    82     
    83     for (int i = 1; i <= m; ++i)
    84     {
    85         static int x, y;
    86         static lnt w;
    87         
    88         scanf("%d%d%lld", &x, &y, &w);
    89         
    90         addEdge(x, y, w);
    91         addEdge(y, x, w);
    92     }
    93     
    94     dfs(1);
    95     
    96     gauss();
    97     
    98     solve();
    99 }

    @Author: YouSiki

  • 相关阅读:
    Android学习笔记【07】【四大组件之广播接收者】
    Android Adapter、Activity回传数据、发送短信
    Android学习笔记【06】【四大组件之Activity】
    Android学习笔记【05】【网络编程之二】
    Android学习笔记【04】【网络编程之一】
    Android学习笔记【03】【数据存储与数据展示】
    【转】sql server获取数据库名,表明,表结构
    C# 打开默认浏览器
    winform 重绘listbox
    字符串数组的简单应用,字符换行,c#,asp.net
  • 原文地址:https://www.cnblogs.com/yousiki/p/6363490.html
Copyright © 2020-2023  润新知