首页 > 其他分享 >G. wxhtzdy ORO Tree

G. wxhtzdy ORO Tree

时间:2023-11-06 11:44:07浏览次数:35  
标签:10 le fa int wxhtzdy Tree ORO dep 节点

G. wxhtzdy ORO Tree

After (finally) qualifying for the IOI 2023, wxhtzdy was very happy, so he decided to do what most competitive programmers do: trying to guess the problems that will be on IOI. During this process, he accidentally made a problem, which he thought was really cool.

You are given a tree (a connected acyclic graph) with $n$ vertices and $n-1$ edges. Vertex $i$ ($1 \le i \le n$) has a value $a_i$.

Lets' define $g(u, v)$ as the bitwise or of the values of all vertices on the shortest path from $u$ to $v$. For example, let's say that we want to calculate $g(3, 4)$, on the tree from the first test case in the example. On the path from $3$ to $4$ are vertices $3$, $1$, $4$. Then, $g(3, 4) = a_3 \ | \ a_1 \ | \ a_4$ (here, $|$ represents the bitwise OR operation).

Also, you are given $q$ queries, and each query looks like this:

You are given $x$ and $y$. Let's consider all vertices $z$ such that $z$ is on the shortest path from $x$ to $y$ (inclusive).

Lets define the niceness of a vertex $z$ as the sum of the number of non-zero bits in $g(x, z)$ and the number of non-zero bits in $g(y, z)$. You need to find the maximum niceness among all vertices $z$ on the shortest path from $x$ to $y$.

Since his brain is really tired after solving an output only problem on SIO (he had to do it to qualify for the IOI), he wants your help with this problem.

Input

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

The first line of each test case contains a single integer $n$ ($1 \le n \le 2 \cdot 10^5$) — the number of vertices.

The second line of each test case contains $n$ positive integers $a_1, a_2, \dots, a_n$ ($1 \le a_v \le 10^9$) — the value of each vertex, the $i$-th integer in this line corresponds to the vertex $i$.

Following $n - 1$ lines are the description of a tree.

Each line contains two integers $u$ and $v$ ($1 \le u, v \le n, u \ne v$) — indicating that vertices $u$ and $v$ are connected by an edge.

The next line contains a single integer $q$ ($1 \le q \le 10^5$) — number of queries.

Following $q$ lines contain 2 integers $x, y$ ($1 \le x, y \le n$) — the vertices $x$ and $y$ for each query.

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

It is guaranteed that the sum of $q$ over all test cases does not exceed $10^5$.

Output

For each test case output $q$ integers, each of which is the answer to the corresponding query.

Examples

input

3
4
1 2 3 4
1 3
1 2
1 4
3
1 1
1 3
1 4
3
7 6 3
3 1
2 1
4
1 1
1 2
1 3
2 3
1
4
1
1 1

output

2 4 3 
6 6 6 6 
2 

input

3
7
4 7 7 4 10 8 10
6 1
3 1
2 1
7 4
1 5
4 2
4
7 5
2 3
4 5
2 5
6
9 5 6 2 4 6
5 1
2 1
1 6
4 3
1 3
4
6 1
1 4
4 3
3 5
7
5 1 3 7 5 1 6
2 1
5 4
2 3
3 4
7 6
6 3
2
4 2
7 7

output

8 6 7 7 
6 6 4 7 
6 4 

input 

1
7
6 8 7 2 5 8 7
2 1
3 2
4 3
4 6
4 5
6 7
4
1 5
6 7
4 5
1 4

output

7 7 5 7 

Note

The image below shows the tree from the second example, first test case.

Tree from the second example, first test case

In the first query, we have $x=7$, $y=5$. The shortest path from $7$ to $5$ is $7-4-2-1-5$.

Let's calculate the niceness of vertex $7$ on this path. We have $g(7,7)=a_7=10=(1010)_2$ and $g(5,7)=a_5 \ | \ a_1 \ | \ a_2 \ | \ a_4 \ | \ a_7=10 \ | \ 4 \ | \ 7 \ | \ 4 \ | \ 10=15=(1111)_2$, so its niceness is equal to $2 + 4 = 6$.

Now let's calculate the niceness of vertex $4$ on this path. We have $g(7,4)=a_7 \ | \ a_4=10 \ | \ 4=14=(1110)_2$ and $g(5,4)=a_5 \ | \ a_1 \ | \ a_2 \ | \ a_4=10 \ | \ 4 \ | \ 7 \ | \ 4=15=(1111)_2$, so its niceness is equal to $3 + 4 = 7$.

Now let's calculate the niceness of vertex $2$ on this path. We have $g(7,2)=a_7 \ | \ a_4 \ | \ a_2=10 \ | \ 4 \ | \ 7=15=(1111)_2$ and $g(5,2)=a_5 \ | \ a_1 \ | \ a_2=10 \ | \ 4 \ | \ 7=15=(1111)_2$, so its niceness is equal to $4 + 4 = 8$.

Now let's calculate the niceness of vertex $1$ on this path. We have $g(7,1)=a_7 \ | \ a_4 \ | \ a_2 \ | \ a_1=10 \ | \ 4 \ | \ 7 \ | \ 4=15=(1111)_2$ and $g(5,1)=a_5 \ | \ a_1=10 \ | \ 4=14=(1110)_2$, so its niceness is equal to $4 + 3 = 7$.

Finally, let's calculate the niceness of vertex $5$ on this path. We have $g(7,5)=a_7 \ | \ a_4 \ | \ a_2 \ | \ a_1 \ | \ a_5=10 \ | \ 4 \ | \ 7 \ | \ 4 \ | \ 10=15=(1111)_2$ and $g(5,5)=a_5=10=(1010)_2$, so its niceness is equal to $4 + 2 = 6$.

The maximum niceness on this path is at vertex $2$, and it is $8$.

 

解题思路

  一开始想着按位来考虑,结果发现这样并不好做。实际上题解给出的做法挺暴力的,但不好想到。

  注意到 $a_i$ 最大为 $10^9$,意味着在二进制下 $a_i$ 最多有 $30$ 位。那么从 $x$ 到 $y$ 的路径中最多只需考虑 $2 \times 30$ 个节点作为中间节点 $z$。这是因为最多有 $30$ 个节点使得 $g(x,z)$ 为 $1$ 的位多 $1$,即那些从 $x$ 到 $y$ 的路径中某一位第一次出现 $1$ 的节点(离 $x$ 最近),而其他的节点完全可以由这 $30$ 个节点来表示(因为不改变 $g(x,z)$ 的结果)。同理分析 $g(y,z)$。当找到这些节点后,直接暴力枚举当作 $z$,计算 $g(x,z) + g(y,z)$ 取最大值即可。

  问题是如何找到这些节点,以及如何快速计算 $g(x,z)$。由于是关于树上的路径问题,因此参考求 $\text{lca}$ 用到的倍增思想。

  定义 $f(u,i)$ 表示从 $u$ 到树根的路径上距离 $u$ 最近的且权值的第 $i$ 位是 $1$ 的节点。分情况讨论,如果 $a_u$ 的第 $i$ 位是 $1$,那么很明显有 $f(u,i) = u$;否则考虑 $u$ 的父节点 $p_u$,那么有 $f(u,i) = f(p_u,i)$。$f(u,i)$ 可以借助 bfs 以 $O(n \log{A})$ 的时间复杂度预处理出来。

  定义 $h(u,i)$ 表示从 $u$ 到往上跳 $2^i$ 步的路径中所有节点权值的按位或结果(不包括节点 $u$ 的权值)。首先考虑从 $u$ 到往上跳 $2^i$ 步的路径上的中间节点,即从 $u$ 到往上跳 $2^{i-1}$ 步后的节点 $\text{fa}(u,i-1)$,这一半路径的按位或结果就是 $h(u,i-1)$,另外一半路径的按位或结果就是 $h(\text{fa}(u,i-1),i-1)$,因此有 $h(u,i) = h(u,i-1) \mid h(\text{fa}(u,i-1),i-1)$。$h(u,i)$ 可以借助 bfs 以 $O(n \log{n})$ 的时间复杂度预处理出来。

  假设 $p = \text{lca}(x,z)$,那么要计算 $g(x,z)$,只需借助 $h$ 数组分别求从 $x$ 到 $p$ 以及从 $z$ 到 $p$ 路径上的权值按位或,具体做法与求最近公共祖先 $p$ 类似。

  有一个疑问的地方就是,由于 $g(u,i)$ 得到的是从 $u$ 到树根这条路径上距离 $u$ 最近的节点,如果在 $x$ 到 $y$ 的路径上距离 $x$ 最近的那个节点在 $p$ 到 $y$ 的路径上($p = \text{lca}(x,y)$),那很明显通过 $f$ 数组是得不到的,如下图权值为 $1$ 的红色节点:

  实际上对于这些距离 $x$ 最近但在 $p$ 到 $y$ 的路径上的节点,假设为 $z'$,如果 $z'$ 也是距离 $y$ 最近的节点那么会被选择作为 $z$。如果不是距离 $y$ 最近的节点,意味着 $a_{z'}$ 中为 $1$ 的位,都存在与之对应的离 $y$ 更近的节点,假设这些节点中距离 $z'$ 最近的是 $z''$,很明显有 $g(y,z') = g(y,z'')$,$g(x,z'') + g(y,z'') \geq g(x,z') + g(y,z')$,因此 $z'$ 不会选作为 $z$。同理分析 $y$。因此只需考虑从该节点到树根路径上的距离最近的节点即可,当然要满足节点在 $x$ 到 $y$ 的路径上,即节点的深度不能小于 $p$ 的深度。

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

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

typedef long long LL;

const int N = 2e5 + 10, M = N * 2;

int w[N];
int head[N], e[M], ne[M], idx;
int fa[N][18], dep[N], s[N][18], g[N][30];
int q[N];

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

int lca(int a, int b) {
    if (dep[a] < dep[b]) swap(a, b);
    for (int i = 17; i >= 0; i--) {
        if (dep[fa[a][i]] >= dep[b]) a = fa[a][i];
    }
    if (a == b) return a;
    for (int i = 17; i >= 0; i--) {
        if (fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i];
    }
    return fa[a][0];
}

int query(int a, int b) {
    if (dep[a] < dep[b]) swap(a, b);
    int ret = w[a] | w[b];
    for (int i = 17; i >= 0; i--) {
        if (dep[fa[a][i]] >= dep[b]) {
            ret |= s[a][i];
            a = fa[a][i];
        }
    }
    if (a == b) return __builtin_popcount(ret);
    for (int i = 17; i >= 0; i--) {
        if (fa[a][i] != fa[b][i]) {
            ret |= s[a][i] | s[b][i];
            a = fa[a][i], b = fa[b][i];
        }
    }
    ret |= s[a][0] | s[b][0];
    return __builtin_popcount(ret);
}

void solve() {
    int n, m;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", w + i);
    }
    memset(head, -1, n + 10 << 2);
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        scanf("%d %d", &u, &v);
        add(u, v), add(v, u);
    }
    memset(dep, 0x3f, n + 10 << 2);
    dep[0] = 0, dep[1] = 1;
    int hh = 0, tt = -1;
    q[++tt] = 1;
    while (hh <= tt) {
        int u = q[hh++];
        for (int i = head[u]; i != -1; i = ne[i]) {
            if (dep[e[i]] > dep[u] + 1) {
                dep[e[i]] = dep[u] + 1;
                q[++tt] = e[i];
                fa[e[i]][0] = u;
                s[e[i]][0] = w[u];
                for (int j = 1; j <= 17; j++) {
                    fa[e[i]][j] = fa[fa[e[i]][j - 1]][j - 1];
                    s[e[i]][j] = s[e[i]][j - 1] | s[fa[e[i]][j - 1]][j - 1];
                }
            }
        }
        for (int i = 0; i <= 29; i++) {
            g[u][i] = g[fa[u][0]][i];
            if (w[u] >> i & 1) g[u][i] = u;
        }
    }
    scanf("%d", &m);
    while (m--) {
        int a, b;
        scanf("%d %d", &a, &b);
        int p = lca(a, b), ret = 0;
        for (int i = 0; i <= 29; i++) {
            if (dep[g[a][i]] >= dep[p]) ret = max(ret, query(a, g[a][i]) + query(b, g[a][i]));
            if (dep[g[b][i]] >= dep[p]) ret = max(ret, query(a, g[b][i]) + query(b, g[b][i]));
        }
        printf("%d ", ret);
    }
    printf("\n");
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces round #900 (Div.3) Editorial:https://codeforces.com/blog/entry/120813

  Codeforces Round 900 (Div. 3) G:https://zhuanlan.zhihu.com/p/658961812

标签:10,le,fa,int,wxhtzdy,Tree,ORO,dep,节点
From: https://www.cnblogs.com/onlyblues/p/17812285.html

相关文章

  • 【刷题笔记】101. Symmetric Tree
    题目Givenabinarytree,checkwhetheritisamirrorofitself(ie,symmetricarounditscenter).Forexample,thisbinarytree[1,2,2,3,4,4,3]issymmetric:1/\22/\/\3443Butthefollowing[1,2,2,null,3,null,3]isnot:1......
  • cf1709E. XOR Tree(启发式合并入门)
    cf1709E.XORTree贪心是显然的,关键是如何合并两棵子树的信息,可以采用启发式合并。#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<map>#include<vector>#include<set>#include<ctime>#include<unordered_ma......
  • Binary Tree Level Order Traversal
    SourceGivenabinarytree,returnthelevelordertraversalofitsnodes'values.(ie,fromlefttoright,levelbylevel).ExampleGivenbinarytree{3,9,20,#,#,15,7},3/\920/\157returnitslevelordertraversala......
  • 【刷题笔记】100. Same Tree
    题目Giventwobinarytrees,writeafunctiontocheckiftheyarethesameornot.Twobinarytreesareconsideredthesameiftheyarestructurallyidenticalandthenodeshavethesamevalue.Example1:Input:11/\/\......
  • 【刷题笔记】98. Validate Binary Search Tree
    题目Givenabinarytree,determineifitisavalidbinarysearchtree(BST).AssumeaBSTisdefinedasfollows:Theleftsubtreeofanodecontainsonlynodeswithkeys lessthan thenode'skey.Therightsubtreeofanodecontainsonlynodeswith......
  • Oracle中B-tree索引的访问方法(一)-- 索引逻辑结构
    B-tree索引的逻辑结构1.1B-tree索引依据不同的维度,我们可以对索引进行相应的分类。比如,根据索引键值是否允许有重复值,可以分为唯一索引和非唯一索引;根据索引是由单个列,还是由多个列构成,又可以分为单列索引和组合索引(也称之为联合索引);而从索引的数据组织结构上来分类,则最常见的是B-......
  • A. Copil Copac Draws Trees
    A.CopilCopacDrawsTrees题目大意:给出一个树边序列,要求你从1号节点建树,对于每条边只有两个端点中有一个绘制了才可以绘制此边思路:这题思路不难,但以前写图太少,遍历被卡,给每个边按序列编号,dfs如果该边的编号大于上条边\(ans++\)code:intn;vector<pii>a[N];intans[N]=......
  • vim 的nerdtree插件中如何显示当前打开的文件路径?
    树形目录nerdtree插件中如何显示当前打开的文件路径?类似这样:只需在.vimrc文件中加入下面3行就可以了"设置NerdTreemap<F3>:NERDTreeMirror<CR>map<F3>:NERDTreeToggle<CR>map<leader>r:NERDTreeFind<cr>......
  • TreeMap
    TreeMap是Map家族中的一员,也是用来存放key-value键值对的。平时在工作中使用的可能并不多,它最大的特点是遍历时是有顺序的,根据key的排序规则来TreeMap是一个双列集合,是Map的子类。底层由红黑树结构构成。TreeMap是一个基于key有序的keyvalue散列表。map根据其键的自然顺序排......
  • CF1039D You Are Given a Tree
    CF1039DYouAreGivenaTree更好的阅读体验一种神奇套路:对答案根分,根分的依据是链的长度和答案大致是一个成反比的关系。考虑确定了\(k\)怎么做。因为一个点只能在一条链里,所以dfs的时候如果能拼成一条链就一定会拼成一条链,不然就把贡献传给父亲继续尝试。对于\(k\)比......