【每日一题】New Year Tree 题解(树链剖分 线段树 状压)
New Year Tree
https://ac.nowcoder.com/acm/problem/111259
Description
给一棵树,根为1,每个节点有一种颜色,有两种操作:
- 将该节点x及其子树的颜色都变为y
- 查询节点x及其子树有多少种颜色
Solution
颜色的范围为 (), 不妨用二进制上的每一位去代表每一种颜色是否存在
那么检查有多少种颜色只需要统计二进制的1个数,用函数 即可
由于是树上的操作,先进行树链剖分,将树上操作改为 序列上的区间操作
那么就转化为经典的线段树问题,用线段树维护并进行区间位运算即可。
Code
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 4e5 + 5;
const int mod = 998244353;
vector<int> G[N];
int L[N], R[N], rk[N], a[N], tot;
struct node {
int l, r;
ll val;
bool lazy;
}t[N << 2];
void dfs(int u, int par) {
L[u] = ++tot;
rk[tot] = u;
for(auto &v : G[u]) {
if(par == v) continue;
dfs(v, u);
}
R[u] = tot;
}
void push_down(int rt) {
if(t[rt].lazy) {
t[rt << 1].lazy = t[rt << 1 | 1].lazy = t[rt].lazy;
t[rt << 1].val = t[rt << 1 | 1].val = t[rt].val;
t[rt].lazy = false;
}
}
void push_up(int rt) {
t[rt].val = t[rt << 1].val | t[rt << 1 | 1].val;
}
void build(int rt, int l, int r) {
t[rt].l = l, t[rt].r = r;
if(l == r) {
t[rt].val |= (1LL << a[rk[l]]);
return ;
}
int mid = t[rt].l + t[rt].r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
push_up(rt);
}
void update(int rt, int ql, int qr, int c) {
if(ql <= t[rt].l && qr >= t[rt].r) {
t[rt].val = (1LL << c);
t[rt].lazy = true;
return ;
}
push_down(rt);
int mid = t[rt].l + t[rt].r >> 1;
if(qr <= mid) {
update(rt << 1, ql, qr, c);
} else if(ql > mid) {
update(rt << 1 | 1, ql, qr, c);
} else {
update(rt << 1, ql, mid, c);
update(rt << 1 | 1, mid + 1, qr, c);
}
push_up(rt);
}
ll query(int rt, int ql, int qr) {
if(ql <= t[rt].l && qr >= t[rt].r) {
return t[rt].val;
}
push_down(rt);
int mid = t[rt].l + t[rt].r >> 1;
if(qr <= mid) {
return query(rt << 1, ql, qr);
} else if(ql > mid) {
return query(rt << 1 | 1, ql, qr);
} else {
return (query(rt << 1, ql, mid) | query(rt << 1 | 1, mid + 1, qr));
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int n, m; cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
for(int i = 1; i <= n - 1; i++) {
int u, v; cin >> u >> v;
G[u].emplace_back(v);
G[v].emplace_back(u);
}
dfs(1, 0);
build(1, 1, n);
for(int i = 1; i <= m; i++) {
int op, x, y; cin >> op;
if(op == 1) {
cin >> x >> y;
update(1, L[x], R[x], y);
} else {
cin >> x;
cout << __builtin_popcountll(query(1, L[x], R[x])) << '\n';
}
}
return 0;
} Kurisu与牛客的每日一题 文章被收录于专栏
每日一题
