題意:一棵無向樹,輸入點數和操作數,下面一行n個值代表每個點的權。下面n-1行是樹邊。操作分為 0 x w ,表示把點x的權改為w; k a b , 求出從a到b的路徑中,第k大的點權。
題解:lca+排序
居然直接暴力就可以過了,每次詢問将lca路徑中的點權排序即可。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
#define pii pair<int, int>
using namespace std;
const int MAXN = 8e4 + 5;
int n, q;
vector<int> v[MAXN];
int fa[MAXN][31], dep[MAXN];
void init() {
for (int i = 1; i <= n; i++) v[i].clear();
// memset(fa, 0, sizeof(fa));
// memset(cost, 0, sizeof(cost));
// memset(dep, 0, sizeof(dep));
}
void dfs(int root, int fno) { //1 0
fa[root][0] = fno;
dep[root] = dep[fa[root][0]] + 1;
for (int i = 1; i < 31; ++i) {
fa[root][i] = fa[fa[root][i - 1]][i - 1];
}
int sz = v[root].size();
for (int i = 0; i < sz; ++i) {
if (v[root][i] == fno) continue;
dfs(v[root][i], root);
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
int tmp = dep[y] - dep[x];
for (int j = 0; tmp; ++j, tmp >>= 1)
if (tmp & 1) y = fa[y][j];
if (y == x) return x;
for (int j = 30; j >= 0 && y != x; --j) {
if (fa[x][j] != fa[y][j]) {
x = fa[x][j];
y = fa[y][j];
}
}
return fa[x][0];
}
int a[MAXN], k;
vector<int> vv;
int main() {
while (~scanf("%d%d", &n, &q)) {
init();
int x, y;
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 1; i < n; i++) {
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs(1, 0);
while (q--) {
scanf("%d%d%d", &k, &x, &y);
if (k == 0) a[x] = y;
else {
int pa = lca(x, y);
vv.clear();
vv.push_back(a[pa]);
while (x != pa) {
vv.push_back(a[x]);
x = fa[x][0];
}
while (y != pa) {
vv.push_back(a[y]);
y = fa[y][0];
}
if (vv.size() < k) puts("invalid request!");
else {
sort(vv.begin(), vv.end());
printf("%d\n", vv[vv.size() - k]);
}
}
}
}
return 0;
}