【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=5338
https://loj.ac/problem/2577
【题解】
可以开两棵可持久化权值线段树,一棵记dfs序维护子树信息,另一棵记欧拉序维护链信息。在开先段树的时候左边的二进制首位为 0 0 ,右边为 1 1 。
对于一次询问,贪心向下选取就行了。
时间复杂度 O(N∗31) O ( N ∗ 31 )
【代码】
# include
# define ll long long
# define ui unsigned
# define inf 0x3f3f3f3f
# define N 200010
# define K 20
using namespace std;
int read(){
int tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') fh = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9'){tmp = tmp * 10 + ch - '0'; ch = getchar(); }
return tmp * fh;
}
struct Edge{
int data, next;
}e[N];
struct Tree{
int pl, pr, size;
}T[N * 64];
int rt1[N], rt2[N], in[N], out[N], p[N], n, q, ti, head[N], place, w[N], dad[N][K + 1], dep[N];
void build(int u, int v){
e[++place].data = v; e[place].next = head[u]; head[u] = place;
}
void dfs(int x, int fa){
in[x] = ++ti; p[ti] = x;
dad[x][0] = fa; dep[x] = dep[fa] + 1;
for (int ed = head[x]; ed != 0; ed = e[ed].next)
if (e[ed].data != fa) dfs(e[ed].data, x);
out[x] = ++ti; p[ti] = -x;
}
void pre(){
for (int i = 1, j = 1; j * 2 <= n; i++, j *= 2)
for (int k = 1; k <= n; k++)
dad[k][i] = dad[dad[k][i - 1]][i - 1];
}
int lca(int x, int y){
if (dep[x] > dep[y]) swap(x, y);
for (int i = K; i >= 0; i--)
if (dep[dad[y][i]] >= dep[x])
y = dad[y][i];
if (x == y) return x;
for (int i = K; i >= 0; i--)
if (dad[y][i] != dad[x][i])
x = dad[x][i], y = dad[y][i];
return dad[x][0];
}
void extend(int &p, int las, int num, int tag, int k){
p = ++place;
T[p].size = T[las].size + tag;
if (k >= 0){
if ((num & (1 << k)) == 0){
extend(T[p].pl, T[las].pl, num, tag, k - 1);
T[p].pr = T[las].pr;
}
else {
extend(T[p].pr, T[las].pr, num, tag, k - 1);
T[p].pl = T[las].pl;
}
}
}
ui query1(int p1, int p2, int num, int k){
if (k < 0) return 0;
if ((num & (1 << k)) == 0){
if (T[T[p1].pr].size - T[T[p2].pr].size != 0)
return query1(T[p1].pr, T[p2].pr, num, k - 1) + (1 << k);
else return query1(T[p1].pl, T[p2].pl, num, k - 1);
}
else {
if (T[T[p1].pl].size - T[T[p2].pl].size != 0)
return query1(T[p1].pl, T[p2].pl, num, k - 1) + (1 << k);
else return query1(T[p1].pr, T[p2].pr, num, k - 1);
}
}
ui query2(int p1, int p2, int p3, int p4, int num, int k){
if (k < 0) return 0;
if ((num & (1 << k)) == 0){
if (T[T[p1].pr].size + T[T[p2].pr].size - T[T[p3].pr].size - T[T[p4].pr].size != 0)
return query2(T[p1].pr, T[p2].pr, T[p3].pr, T[p4].pr, num, k - 1) + (1 << k);
else return query2(T[p1].pl, T[p2].pl, T[p3].pl, T[p4].pl, num, k - 1);
}
else {
if (T[T[p1].pl].size + T[T[p2].pl].size - T[T[p3].pl].size - T[T[p4].pl].size != 0)
return query2(T[p1].pl, T[p2].pl, T[p3].pl, T[p4].pl, num, k - 1) + (1 << k);
else return query2(T[p1].pr, T[p2].pr, T[p3].pr, T[p4].pr, num, k - 1);
}
}
int main(){
// freopen("B.in", "r", stdin);
// freopen(".out", "w", stdout);
n = read(), q = read();
for (int i = 1; i <= n; i++) w[i] = read();
for (int i = 1; i < n; i++){
int u = read(), v = read();
build(u, v); build(v, u);
}
place = 0;
dfs(1, 0);
for (int i = 1; i <= ti; i++){
if (p[i] > 0){
extend(rt1[i], rt1[i - 1], w[p[i]], 1, 30);
extend(rt2[i], rt2[i - 1], w[p[i]], 1, 30);
}
else {
rt1[i] = rt1[i - 1];
extend(rt2[i], rt2[i - 1], w[-p[i]], -1, 30);
}
}
pre();
for (int i = 1; i <= q; i++){
int op = read(), x, y, tmp;
if (op == 1){
x = read(), tmp = read();
printf("%u\n", query1(rt1[out[x]], rt1[in[x] - 1], tmp, 30));
}
else {
x = read(), y = read(), tmp = read();
int l = lca(x, y);
printf("%u\n", query2(rt2[in[x]], rt2[in[y]], rt2[in[l]], rt2[in[dad[l][0]]], tmp, 30));
}
}
return 0;
}