题意:有一颗以1号节点为根的树,每一个节点有一个自己的颜色,求出节点v的子数上颜色出现次数>=k的颜色种类。
题解:使用莫队处理这个问题,将树转变成DFS序区间,然后就是开一个数据记录下出现次数为k次的颜色数目,查询的时候直接返回这个数组中的对应的值就行了。
注意的就是记得将节点的颜色传递给dfs序对应位置的颜色。 这个忘记了找了好久的bug。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define max3(a,b,c) max(a,max(b,c)) 12 #define min3(a,b,c) min(a,min(b,c)) 13 #define _S(X) cout << x << ' '; 14 #define __S(x) cout << x << endl; 15 typedef pair<int,int> pll; 16 const int INF = 0x3f3f3f3f; 17 const LL mod = (int)1e9+7; 18 const int N = 2e5 + 100; 19 int in[N], out[N], col[N], cc[N], cnt[N], num[N], ans[N]; 20 vector<int> son[N]; 21 int tot, n, m, blo; 22 struct Node{ 23 int l, r, id, k; 24 }q[N]; 25 bool cmp(Node x1, Node x2){ 26 if(x1.l/blo != x2.l/blo) return x1.l/blo < x2.l/blo; 27 return x1.r < x2.r; 28 } 29 void Add(int c){ 30 num[++cnt[c]]++; 31 } 32 void Remove(int c){ 33 num[cnt[c]--]--; 34 } 35 void dfs(int o, int u){ 36 in[u] = ++tot; 37 cc[tot] = col[u]; 38 for(int i = 0; i < son[u].size(); i++){ 39 if(son[u][i] == o) continue; 40 dfs(u, son[u][i]); 41 } 42 out[u] = tot; 43 } 44 int main(){ 45 scanf("%d%d", &n, &m); 46 for(int i = 1; i <= n; i++) 47 scanf("%d", &col[i]); 48 blo = sqrt(n); 49 int u, v; 50 for(int i = 1; i < n; i++){ 51 scanf("%d%d", &u, &v); 52 son[u].pb(v); 53 son[v].pb(u); 54 } 55 dfs(-1,1); 56 for(int i = 1; i <= m; i++){ 57 q[i].id = i; 58 scanf("%d%d", &u, &v); 59 q[i].k = v; 60 q[i].l = in[u]; 61 q[i].r = out[u]; 62 } 63 sort(q+1, q+1+m, cmp); 64 // cout << "vujgfuy" << endl; 65 int l = 1, r = 0; 66 for(int i = 1; i <= m; i++) 67 { 68 while(r < q[i].r) Add(cc[++r]); 69 while(r > q[i].r) Remove(cc[r--]); 70 while(l < q[i].l) Remove(cc[l++]); 71 while(l > q[i].l) Add(cc[--l]); 72 ans[q[i].id] = num[q[i].k]; 73 } 74 for(int i = 1; i <= m; i++) 75 printf("%d ", ans[i]); 76 return 0; 77 }