【HDU-6291/2018CCPC女生赛E】对称数(散列+树上主席树)

题目链接:https://vjudge.net/problem/HDU-6291

思路

偶数个 \(x\) 异或起来一定是 \(0\)。因此只需要在链上找第一个出现次数为偶数次的点即可。

通过将一个数变为另一个极大的数,来满足异或后的和不会碰撞,例如,将 \(1\) 变为 \(114\),将 \(2\)变为 \(514\),将 \(3\) 变为 \(1919\),来保证 \(1 \bigoplus 2 \bigoplus 3 = 0\) 的情况不会出现导致干扰。

然后想到在树上搞颗权值线段树解决问题,如果做过SPOJ系列的求数上路径第 \(k\) 大的问题的话就能很快想到树上主席树。绕口令

花絮

我:这题可以线段树分裂合并乱搞。

juraws:那你快上

(半小时后)

我:不好意思样例没过好像复杂度也不太对劲……

另外,中途求 \(LCA\) 还挂了好几发,需要将初始的 \(fa\) 树组置0。

AC代码

#include <bits/stdc++.h>

typedef unsigned long long ull;
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXR = 2e5 + 1;

ull Newrnd() {
    return ((ull) rand() << 45) | ((ull) rand() << 30) | (rand() << 15) | rand();
}


ull val2newval[MAXN], pre_val2newval[MAXN];

class HJT {
public:
    int ch[MAXN * 70][2], tot = 0;
    ull sum[MAXN * 70];

    void init() {
        memset(ch, 0, sizeof(ch));
        memset(sum, 0, sizeof(sum));
        tot = 0;
    }

    inline void push_up(int rt) {
        sum[rt] = sum[ch[rt][0]] ^ sum[ch[rt][1]];
    }

    int update(int rt, int pos, ull val, int be, int en) {
        int nrt = ++tot;
        ch[nrt][0] = ch[nrt][1] = 0;
        sum[nrt] = (ull) 0;// = rnd[nrt] = 0;
        if (be == en) {
            sum[nrt] = sum[rt] ^ val;
            return nrt;
        }
        int mid = (be + en) >> 1;
        if (pos <= mid) {
            ch[nrt][0] = update(ch[rt][0], pos, val, be, mid);
            ch[nrt][1] = ch[rt][1];
        } else {
            ch[nrt][0] = ch[rt][0];
            ch[nrt][1] = update(ch[rt][1], pos, val, mid + 1, en);
        }
        push_up(nrt);
        return nrt;
    }

    int query(int lrt, int rrt, int fa, int faa, int be, int en) {
        if (be >= en) return be;
        int mid = (be + en) >> 1;
        ull delta1 = sum[ch[lrt][0]] ^sum[ch[rrt][0]] ^sum[ch[fa][0]] ^sum[ch[faa][0]];
        ull delta2 = pre_val2newval[mid] ^pre_val2newval[be - 1];
        if (delta1 != delta2) return query(ch[lrt][0], ch[rrt][0], ch[fa][0], ch[faa][0], be, mid);
        else return query(ch[lrt][1], ch[rrt][1], ch[fa][1], ch[faa][1], mid + 1, en);
    }


} tree;

struct Edge {
    int to, nex;
} e[MAXN << 1];
int head[MAXN], tol;

void addEdge(int u, int v) {
    e[tol].to = v, e[tol].nex = head[u], head[u] = tol, tol++;
}


int root[MAXN];
int dep[MAXN], fa[MAXN][32], lg[MAXN];
int a[MAXN];

void dfs(int u, int f) {
    fa[u][0] = f;
    dep[u] = dep[f] + 1;
    root[u] = tree.update(root[f], a[u], val2newval[a[u]], 1, MAXR);
    for (int i = 1; i <= lg[dep[u]]; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for (int i = head[u]; ~i; i = e[i].nex) {
        int v = e[i].to;
        if (v == f) continue;
        dfs(v, u);
    }
}

int LCA(int u, int v) {
    if (dep[u] < dep[v]) swap(u, v);
    while (dep[u] > dep[v]) u = fa[u][lg[dep[u] - dep[v]] - 1];
    if (u == v) return u;
    for (int k = lg[dep[u]] - 1; k >= 0; k--) {
        if (fa[u][k] != fa[v][k]) u = fa[u][k], v = fa[v][k];
    }
    return fa[u][0];
}


int main() {
    srand(114514);  // random
    for (int i = 1; i < MAXN; i++) lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
    pre_val2newval[0] = 0;
    for (int i = 1; i < MAXN; i++) val2newval[i] = Newrnd(), pre_val2newval[i] = pre_val2newval[i - 1] ^ val2newval[i];

    int T;
    scanf("%d", &T);

    while (T--) {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) head[i] = -1;   // init graph
        memset(fa, 0,  sizeof(fa));

        tol = 0; // init graph
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 2; i <= n; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            addEdge(u, v), addEdge(v, u);
        }
        tree.tot = 0; // init HJT

        root[0] = 0;
        dfs(1, 0);

        while (m--) {
            int u, v;
            scanf("%d%d", &u, &v);

            int lca = LCA(u, v);
          //  if (dep[u] > dep[v]) swap(u, v);
            printf("%d\n", tree.query(root[u], root[v], root[lca], root[fa[lca][0]], 1, MAXR));
        }

    }
}
posted @ 2020-12-16 17:52  tudouuuuu  阅读(71)  评论(0编辑  收藏  举报