首页 > 其他分享 >G. Yasya and the Mysterious Tree

G. Yasya and the Mysterious Tree

时间:2024-06-05 19:56:07浏览次数:20  
标签:10 le int tr Tree 异或 Mysterious oplus Yasya

G. Yasya and the Mysterious Tree

Yasya was walking in the forest and accidentally found a tree with $n$ vertices. A tree is a connected undirected graph with no cycles.

Next to the tree, the girl found an ancient manuscript with $m$ queries written on it. The queries can be of two types.

The first type of query is described by the integer $y$. The weight of each edge in the tree is replaced by the bitwise exclusive OR of the weight of that edge and the integer $y$.

The second type is described by the vertex $v$ and the integer $x$. Yasya chooses a vertex $u$ ($1 \le u \le n$, $u \neq v$) and mentally draws a bidirectional edge of weight $x$ from $v$ to $u$ in the tree.

Then Yasya finds a simple cycle in the resulting graph and calculates the bitwise exclusive OR of all the edges in it. She wants to choose a vertex $u$ such that the calculated value is maximum. This calculated value will be the answer to the query. It can be shown that such a cycle exists and is unique under the given constraints (independent of the choice of $u$). If an edge between $v$ and $u$ already existed, a simple cycle is the path $v \to u \to v$.

Note that the second type of query is performed mentally, meaning the tree does not change in any way after it.

Help Yasya answer all the queries.

Input

The first line contains an integer $t$ ($1 \le t \le 10^4$) — the number of test cases.

The descriptions of the test cases follow.

The first line of each test case contains two integers $n$, $m$ ($2 \le n \le 2 \cdot 10^5$, $1 \le m \le 2 \cdot 10^5$) — the number of vertices in the tree and the number of queries.

The next $n - 1$ lines of each test case contain three integers $v$, $u$, $w$ ($1 \le v, u \le n$, $1 \le w \le 10^9$) — the ends of some edge in the tree and its weight.

It is guaranteed that the given set of edges forms a tree.

The next $m$ lines of each test case describe the queries:

  • ^ $y$ ($1 \le y \le 10^9$) — parameter of the first type query;
  • ? $v$ $x$ ($1 \le v \le n$, $1 \le x \le 10^9$) — parameters of the second type query.

It is guaranteed that the sum of $n$ over all test cases does not exceed $2 \cdot 10^5$. The same is guaranteed for $m$.

Output

For each test case, output the answers to the queries of the second type.

Examples

input

2
3 7
1 2 1
3 1 8
^ 5
? 2 9
^ 1
? 1 10
^ 6
? 3 1
? 2 9
5 6
1 2 777
3 2 2812
4 1 16
5 3 1000000000
^ 4
? 3 123
? 5 1000000000
^ 1000000000
? 1 908070
? 2 1

output

13 15 11 10 
1000000127 2812 999756331 999999756 

input

3
8 4
8 6 3
6 3 4
2 5 4
7 6 2
7 1 10
4 1 4
5 1 2
^ 4
^ 7
? 7 8
? 4 10
5 6
3 1 4
2 3 9
4 3 6
5 2 10
? 5 7
^ 1
^ 8
? 4 10
? 1 9
? 3 6
4 2
2 1 4
4 3 5
2 3 4
^ 13
? 1 10

output

14 13 
13 8 11 11 
10 

 

解题思路

  对于询问操作,本质上就是找到一个点 $u \, (u \ne v)$ 使得 $u$、$v$ 两点构成路径的边权异或和,与 $x$ 异或后的结果最大。为了求得任意一条路径的异或和,先通过 dfs 预处理出每个点 $u$ 到根节点(固定节点 $1$ 为根)路径上的异或和 $s_u$。那么任意两点 $u$、$v$ 构成路径的异或和就是 $s_u \oplus s_v$。假设 $p = \mathrm{lca}(u,v)$,路径 $u \to p \to v$ 的异或和就是 $(s_u \oplus s_p) \oplus (s_v \oplus s_p) = s_u \oplus s_v$。

  由于 $s_v$ 和 $x$ 是固定的,所以就是找到一个 $s_u$,使得 $s_u \oplus (s_v \oplus x)$ 的结果最大。这就是一个经典的问题,将每个 $s_u$ 的二进制位从高到低存储到 Trie 中,然后从高位到低位贪心地找到使得异或 $s_v \oplus x$ 结果最大的 $s_u$。又因为 $u \ne v$,因此在查询前需要在 Trie 中删掉 $s_v$,只需逻辑删除即可,即给 Trie 的每个节点开个计数器,在遍历 $s_v$ 的节点时只需对其计数器减 $1$ 即可。查询完后还要再把 $s_v$ 插入到 Trie 中。

  再考虑修改操作对 $s_u$ 的影响。如果 $1 \to u$ 的路径上有偶数条边,显然 $s_u$ 的结果不会改变。否则 $1 \to u$ 的路径上有奇数条边,那么有 $s_u \gets s_u \oplus x$。对于每次修改操作,显然可以先把路径长度为奇数的 $s_u$ 从 Trie 中删除,再插入 $s_u \oplus x$,也显然会超时。干脆根据路径长度的奇偶性维护两个 Trie,当查询偶数的 Trie 时,找的是异或 $s_v \oplus x$ 的最大结果;查询奇数的 Trie 时,找的是异或 $s_v \oplus x \oplus \mathrm{sum}$ 的最大结果,其中 $\mathrm{sum}$ 是前面所有修改操作的异或和。

  AC 代码如下,时间复杂度为 $O((n+m) \log{A})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 5, M = N * 2, K = N * 30;

int h[N], e[M], wt[M], ne[M], idx;
int s[N], d[N];
int tr[2][K][2], cnt[K];

void add(int u, int v, int w) {
    e[idx] = v, wt[idx] = w, ne[idx] = h[u], h[u] = idx++;
}

void modify(int tr[][2], int x, int c){
    int p = 0;
    for (int i = 29; i >= 0; i--) {
        int t = x >> i & 1;
        if (!tr[p][t]) tr[p][t] = ++idx;
        p = tr[p][t];
        cnt[p] += c;
    }
}

void dfs(int u, int p) {
    modify(tr[d[u]], s[u], 1);
    for (int i = h[u]; i != -1; i = ne[i]) {
        int v = e[i];
        if (v == p) continue;
        s[v] = s[u] ^ wt[i];
        d[v] = d[u] ^ 1;
        dfs(v, u);
    }
}

int query(int tr[][2], int x) {
    int p = 0, ret = 0;
    for (int i = 29; i >= 0; i--) {
        int t = x >> i & 1;
        if (cnt[tr[p][t ^ 1]]) p = tr[p][t ^ 1], ret |= 1 << i;
        else p = tr[p][t];
    }
    return ret;
}

void solve() {
    int n, m;
    cin >> n >> m;
    idx = 0;
    memset(h, -1, n + 1 << 2);
    for (int i = 0; i < n - 1; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w), add(v, u, w);
    }
    idx = 0;
    for (int i = 0; i <= 1; i++) {
        for (int j = 0; j < n * 30; j++) {
            tr[i][j][0] = tr[i][j][1] = 0;
        }
    }
    memset(cnt, 0, n * 30 + 1 << 2);
    dfs(1, 0);
    int sum = 0;
    while (m--) {
        char c;
        int x, y;
        cin >> c >> x;
        if (c == '^') {
            sum ^= x;
        }
        else {
            cin >> y;
            modify(tr[d[x]], s[x], -1);    // 先在相应的Trie中删除s[u]
            // 分别查询(u,v)路径长度为偶数、奇数的最大值
            cout << max(query(tr[d[x]], s[x] ^ y), query(tr[d[x] ^ 1], s[x] ^ y ^ sum)) << ' ';
            modify(tr[d[x]], s[x], 1); // 重新插入s[u]
        }
    }
    cout << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 950 (Div. 3) Editorial:https://codeforces.com/blog/entry/130135

标签:10,le,int,tr,Tree,异或,Mysterious,oplus,Yasya
From: https://www.cnblogs.com/onlyblues/p/18233660

相关文章

  • Matrix-Tree 定理
    引入此算法可以解决图上生成树计数问题。值得注意的是,矩阵树定理不能用于存在自环的图。定义设\(G\)是一个图。记邻接矩阵\(A(G)_{i,j}=\#e(i,j),\#e(i,j)\)若\(G\)是无向图记\(D(G)\)表示其度数矩阵,\(D(G)\)满足\(D(G)_{i,i}\)表示第\(i\)点的度数,\(D(G)_{......
  • Git客户端工具:SourceTree for Mac v 4.1.5中文特别版
    SourceTree是一款由Atlassian公司推出的免费的Git和Mercurial版本控制系统的可视化客户端工具。它提供了一种简单易用的方式来管理和查看代码的版本历史,以及进行代码的比较、合并和提交等操作。用户可以通过SourceTree轻松地管理多个代码仓库,并且可以直观地查看代码的变化和提......
  • 100. Same Tree
    Giventherootsoftwobinarytreespandq,writeafunctiontocheckiftheyarethesameornot.Twobinarytreesareconsideredthesameiftheyarestructurallyidentical,andthenodeshavethesamevalue.Example1:Input:p=[1,2,3],q=[1,2......
  • 在 Windows 10 中全局安装 tree 命令
    在Windows10中全局安装tree命令的步骤如下:1.下载TreeforWindows工具包。可以从官方网站https://gnuwin32.sourceforge.net/packages/tree.htm下载最新版本的Binaries.zip压缩包。2.解压下载的Binaries.zip压缩包。在解压后的文件夹中,找到bin目录,里面有一个......
  • trie tree 和 radix tree
    https://eslody.github.io/2021/07/10/基数树-Radix-tree-和前缀树-Trie-tree/trie树为n叉搜索树,搜索路径上的所有节点组成的完整的路径构成了要查找的值。Radix树,即基数树,也称压缩前缀树,是一种提供key-value存储查找的数据结构。与Trie不同的是,它对Trie树进行了空间优化,只有......
  • 线段树入门(Segment Tree)
    线段树入门(SegmentTree)基本线段树与树状数组功能类似,实现了点的修改与区间的查询:首先实现基本的线段树的构建:#include<iostream>#include<vector>usingnamespacestd;classsegmentTree{public:segmentTree(intn,vector<int>nums){size=4*n;......
  • LeetCode 1305. All Elements in Two Binary Search Trees
    原题链接在这里:https://leetcode.com/problems/all-elements-in-two-binary-search-trees/description/题目:Giventwobinarysearchtrees root1 and root2,return alistcontainingalltheintegersfrombothtreessortedin ascending order.Example1:Input:......
  • npm install安装时一直idealTree:npm: sill idealTree buildDeps问题
    解决方案:采用新的镜像地址,进入cmd之后输入:npm命令:npmconfigsetregistryhttps://registry.npmmirror.comyarn命令:yarnconfigsetregistryhttps://registry.npmmirror.com查看配置是完成npmconfiggetregistryyarnconfiggetregistry参考:https:......
  • [数据结构+二叉树+B-Tree和红黑树与B+Tree与hashMap原理+ concurrentHashMap的原理]析
    目录数据结构:你了解过哪些数据结构:这些数据结构的优缺点:二叉树:特点:二叉树适合做磁盘存储吗: 缺点:B-Tree:b-树的查找过程:思考:特点:B+Tree: B+树搜索过程与B树的查询过程没有区别。但实际上有三点不一样:(B+Tree优势)简述B+Tree:不经历IO的情况下,可以直接......
  • CF 947 (Div. 1 + Div. 2) D. Paint the Tree
    时间:24_05_30原题:CodeforcesRound947(Div.1+Div.2)标签:二分/数据结构/[[DFS]]/[[模拟]]/[[树形结构]]题目大意有\(n\)个顶点的树,初始时每个节点都是白色树上有两个棋子,为\(P_A\)和\(P_B\),分别位于\(a\),\(b\)顶点\(P_A\)所在的顶点会被涂成红色,\(P_B\)......