#279. [SYZOI Round1] 滑稽♂树
子树上的问题,考虑dfsdfsdfs序,第kkk大,可以用主席树嘛,支持修改,那就树状数组上套主席树,参考P4175 [CTSC2008]网络管理(树状数组套主席树)
#include <bits/stdc++.h>using namespace std;const int N = 3e4 + 10, maxn = 10000;int head[N], to[N << 1], nex[N << 1], cnt = 1;int l[N], r[N], tot;int a[N], n, m;int root[N], ls[N << 8], rs[N << 8], sum[N << 8], num;int A[N], B[N], cnt1, cnt2;inline void add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++;
}inline int lowbit(int x) {return x & (-x);
}void update(int &rt, int l, int r, int x, int v) {if (!rt) {rt = ++num;}sum[rt] += v;if (l == r) {return; }int mid = l + r >> 1;if (x <= mid) {update(ls[rt], l, mid, x, v);}else {update(rs[rt], mid + 1, r, x, v);}
}void dfs(int rt, int fa) {l[rt] = ++tot;for (int i = l[rt]; i <= n; i += lowbit(i)) {update(root[i], 1, maxn, a[rt], 1);}for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa) {continue;}dfs(to[i], rt);}r[rt] = tot;
}int query1(int l, int r, int k) {if (l == r) {return l;}int cur = 0, mid = l + r >> 1;for (int i = 1; i <= cnt1; i++) {cur -= sum[ls[A[i]]];}for (int i = 1; i <= cnt2; i++) {cur += sum[ls[B[i]]];}if (cur >= k) {for (int i = 1; i <= cnt1; i++) {A[i] = ls[A[i]];}for (int i = 1; i <= cnt2; i++) {B[i] = ls[B[i]];}return query1(l, mid, k);}else {for (int i = 1; i <= cnt1; i++) {A[i] = rs[A[i]];}for (int i = 1; i <= cnt2; i++) {B[i] = rs[B[i]];}return query1(mid + 1, r, k - cur);}
}int query2(int l, int r, int L, int R) {if (l >= L && r <= R) {int res = 0;for (int i = 1; i <= cnt1; i++) {res -= sum[A[i]];}for (int i = 1; i <= cnt2; i++) {res += sum[B[i]];}return res;}int mid = l + r >> 1, res = 0;int A1[100], B1[100];if (L <= mid) {for (int i = 1; i <= cnt1; i++) {A1[i] = A[i];A[i] = ls[A[i]];}for (int i = 1; i <= cnt2; i++) {B1[i] = B[i];B[i] = ls[B[i]];}res += query2(l, mid, L, R);for (int i = 1; i <= cnt1; i++) {A[i] = A1[i];}for (int i = 1; i <= cnt2; i++) {B[i] = B1[i];}}if (R > mid) {for (int i = 1; i <= cnt1; i++) {A1[i] = A[i];A[i] = rs[A[i]];}for (int i = 1; i <= cnt2; i++) {B1[i] = B[i];B[i] = rs[B[i]];}res += query2(mid + 1, r, L, R);for (int i = 1; i <= cnt1; i++) {A[i] = A1[i];}for (int i = 1; i <= cnt2; i++) {B[i] = B1[i];}}return res;
}int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);scanf("%d", &n);for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);}for (int i = 1; i < n; i++) {int x, y;scanf("%d %d", &x, &y);add(x, y);add(y, x);}dfs(1, 0);scanf("%d", &m);for (int i = 1; i <= m; i++) {int op, u, x, y;scanf("%d %d %d", &op, &u, &x);if (op == 1) {cnt1 = cnt2 = 0;for (int i = l[u] - 1; i ; i -= lowbit(i)) {A[++cnt1] = root[i];}for (int i = r[u]; i; i -= lowbit(i)) {B[++cnt2] = root[i];}printf("%d\n", query1(1, maxn, x));}else if (op == 2) {scanf("%d", &y);cnt1 = cnt2 = 0;for (int i = l[u] - 1; i ; i -= lowbit(i)) {A[++cnt1] = root[i];}for (int i = r[u]; i; i -= lowbit(i)) {B[++cnt2] = root[i];}printf("%d\n", query2(1, maxn, x, y));}else {for (int i = l[u]; i <= n; i += lowbit(i)) {update(root[i], 1, maxn, a[u], -1);}a[u] = x;for (int i = l[u]; i <= n; i += lowbit(i)) {update(root[i], 1, maxn, a[u], 1);}}}return 0;
}