zoukankan      html  css  js  c++  java
  • [洛谷P3292] [SCOI2016]幸运数字

    P3292 [SCOI2016]幸运数字

    一颗带点权的树,每次查询指定两个点,求在两个点之间的这条路径(包括两端)上选任意个数能得到的最大异或值。

    做法

    考虑倍增维护LCA,同时维护向上(2^k)的点的线性基,然后查询求LCA时将经过的所有线性基暴力合并即可。

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    template <class T>
    inline void read(T &num)
    {
        bool flag = 0;
        num = 0;
        char c = getchar();
        while ((c < '0' || c > '9') && c != '-')
            c = getchar();
        if (c == '-')
        {
            flag = 1;
            c = getchar();
        }
        num = c - '0';
        c = getchar();
        while (c >= '0' && c <= '9')
            num = (num << 3) + (num << 1) + c - '0', c = getchar();
        if (flag)
            num *= -1;
    }
    template <class T>
    inline void output(T num)
    {
        if (num < 0)
        {
            putchar('-');
            num = -num;
        }
        if (num >= 10)
            output(num / 10);
        putchar(num % 10 + '0');
    }
    template <class T>
    inline void outln(T num)
    {
        output(num);
        putchar('
    ');
    }
    template <class T>
    inline void outps(T num)
    {
        output(num);
        putchar(' ');
    }
    template <class T>
    inline T max(T a, T b)
    {
        return a < b ? b : a;
    }
    typedef long long ll;
    struct basis // 线性基
    {
        typedef ll type;
        static const int W = 62;
        type s[W];
        basis()
        {
            memset(s, 0, sizeof(s));
        }
        void ins(type x) // 向线性基内插入一个数
        {
            for (int i = W; i >= 1; i--)
            {
                if (x >> (i - 1))
                {
                    if (s[i] == 0)
                    {
                        s[i] = x;
                        return;
                    }
                    x ^= s[i];
                }
            }
        }
        type maxxor() // 求线性基内最大xor值
        {
            type ans = 0;
            for (int i = W; i >= 1; i--)
            {
                ans = max(ans, ans ^ s[i]);
            }
            return ans;
        }
    };
    const int N = 20005;
    const int lN = 20;
    int n, q, ln;
    namespace graph // 存图
    {
        int fir[N], to[N * 2], nxt[N * 2], ecnt;
        void add_edge(int u, int v)
        {
            to[++ecnt] = v;
            nxt[ecnt] = fir[u];
            fir[u] = ecnt;
        }
    } // namespace graph
    namespace tree
    {
        ll g[N];                  // g[i]     : i号点的数字
        int dep[N];               // dep[i]   : i号点的深度
        int fa[N][lN];            // fa[i][j] : i号点向上跳2^j到达的节点
        basis b[N][lN];           // b[i][j]  : i号点以上的2^j点的线性基(显然不包括fa[i][j])
        void dfs(int node, int f) // 深搜初始化
        {
            using namespace graph;
            dep[node] = dep[f] + 1;
            fa[node][0] = f;
            b[node][0].ins(g[node]);
            for (int i = 1; i <= ln; i++) // 倍增求2^k次祖先以及路径上数字的线性基
            {
                fa[node][i] = fa[fa[node][i - 1]][i - 1];
                if (!fa[node][i])
                    break;
                for (int j = 1; j <= basis::W; j++)
                {
                    if (b[node][i - 1].s[j])
                        b[node][i].ins(b[node][i - 1].s[j]);
                    if (b[fa[node][i - 1]][i - 1].s[j])
                        b[node][i].ins(b[fa[node][i - 1]][i - 1].s[j]);
                }
            }
            for (int e = fir[node]; e; e = nxt[e])
            {
                if (to[e] == f)
                    continue;
                dfs(to[e], node);
            }
        }
    } // namespace tree
    ll solve(int x, int y)
    {
        using namespace tree;
        basis rtn;
        if (dep[x] < dep[y])
            x ^= y ^= x ^= y;
        for (int k = ln; k >= 0; k--)
            if (dep[fa[x][k]] >= dep[y])
            {
                for (int j = 1; j <= basis::W; j++)
                    if (b[x][k].s[j])
                        rtn.ins(b[x][k].s[j]);
                x = fa[x][k];
            }
        if (x == y)
        {
            rtn.ins(g[x]);
            return rtn.maxxor();
        }
        for (int i = ln; i >= 0; i--)
        {
            if (dep[fa[x][i]] == 0)
                continue;
            if (fa[x][i] == fa[y][i])
                continue;
            for (int j = 1; j <= basis::W; j++)
            {
                if (b[x][i].s[j])
                    rtn.ins(b[x][i].s[j]);
                if (b[y][i].s[j])
                    rtn.ins(b[y][i].s[j]);
            }
            x = fa[x][i];
            y = fa[y][i];
        }
        rtn.ins(g[x]);
        rtn.ins(g[y]);
        rtn.ins(g[fa[x][0]]);
        return rtn.maxxor();
    }
    int main()
    {
        read(n);
        read(q);
        ln = ceil(log(n) / log(2)) + 2;
        for (int i = 1; i <= n; i++)
            read(tree::g[i]);
        for (int i = 1; i < n; i++)
        {
            int x, y;
            read(x);
            read(y);
            graph::add_edge(x, y);
            graph::add_edge(y, x);
        }
        tree::dfs(1, 0);
        while (q--)
        {
            int x, y;
            read(x);
            read(y);
            outln(solve(x, y));
        }
    }
    
  • 相关阅读:
    Redis使用:聚合类型为空时,会自动被Redis删除
    Effective C++: 04设计与声明
    select引起的服务端程序崩溃问题
    Effective C++: 03资源管理
    Effective C++: 02构造、析构、赋值运算
    Effective C++: 01让自己习惯C++
    Centos7.2 安装配置 Tengine(nginx)
    Centos7更新阿里yum源
    Go中函数作为值、类型传递。
    go实现冒泡排序和快速排序
  • 原文地址:https://www.cnblogs.com/water-lift/p/11166488.html
Copyright © 2011-2022 走看看