题意:给出一棵树,每个节点有一个颜色,现在有两种操作,一种是将一棵子树所有节点置为一种颜色,另一种是求一棵子树内的结点颜色数量。
思路:首先处理出每个节点的dfs序转化为线性区间上的问题。然后剩下就是一个裸的线段树问题,用每一个二进制位代表一种颜色,然后结点的权值表示当前区间有多少种颜色,区将合并只需要或运算即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 500000;
//树相关部分
int n, m, dfs_clock;
vector<int> G[MAXN];
int node[MAXN], tim[MAXN][2];
void dfs(int cur, int fa) {
tim[cur][0] = ++dfs_clock;
for(int i = 0; i < G[cur].size(); i++) {
int u = G[cur][i];
if(u == fa) continue;
dfs(u, cur);
}
tim[cur][1] = dfs_clock;
}
//线段树部分
LL col[MAXN<<2], setv[MAXN<<2];
int cal_col(LL col) {
int cnt = 0;
for(int i = 0; i < 63; i++) {
if((1LL<<i) & col) cnt++;
}
return cnt;
}
void pushdown(int o) {
if(setv[o] > 0) {
setv[o<<1] = setv[(o<<1)|1] = setv[o];
setv[o] = 0;
}
}
void maintain(int o, int L, int R) {
col[o] = 0;
if(R > L) col[o] = col[o<<1] | col[(o<<1)|1];
if(setv[o] > 0) col[o] = setv[o];
}
void update(int o, int L, int R, int ql, int qr, int c) {
if(ql<=L && qr>=R) setv[o] = 1LL<<c;
else {
pushdown(o);
int M = (L+R) >> 1;
if(ql<=M) update(o<<1, L, M, ql, qr, c); else maintain(o<<1, L, M);
if(qr>M) update((o<<1)|1, M+1, R, ql, qr, c); else maintain((o<<1)|1, M+1, R);
}
maintain(o, L, R);
}
LL query(int o, int L, int R, int ql, int qr) {
if(setv[o] > 0) return setv[o];
else if(ql<=L && qr>=R) return col[o];
int M = (L+R) >> 1;
LL ans = 0;
if(ql <= M) ans |= query(o<<1, L, M, ql, qr);
if(qr > M) ans |= query((o<<1)|1, M+1, R, ql, qr);
return ans;
}
int main() {
//freopen("input.txt", "r", stdin);
dfs_clock = 0;
cin >> n >> m;
for(int i = 1; i <= n; i++) scanf("%d", &node[i]);
for(int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, -1);
for(int i = 1; i <= n; i++) {
update(1, 1, n, tim[i][0], tim[i][0], node[i]);
}
for(int i = 1; i <= m; i++) {
int op, u, v;
scanf("%d", &op);
if(op == 1) {
scanf("%d%d", &u, &v);
update(1, 1, n, tim[u][0], tim[u][1], v);
}
else {
scanf("%d", &u);
LL ans = query(1, 1, n, tim[u][0], tim[u][1]);
printf("%d\n", cal_col(ans));
}
}
return 0;
}