Description
In this problem we consider a rooted tree with N vertices. The vertices are numbered from 1 to N, and vertex 1 represents the root. There are integer weights on each vectice. Your task is to answer a list of queries, for each query, please tell us among all the vertices in the subtree rooted at vertice u, how many different kinds of weights appear exactly K times?
Input
The first line of the input contains an integer T( T<= 5 ), indicating the number of test cases.
For each test case, the first line contains two integers N and K, as described above. ( 1<= N <= 10 5, 1 <= K <= N )
Then come N integers in the second line, they are the weights of vertice 1 to N. ( 0 <= weight <= 10 9 )
For next N-1 lines, each line contains two vertices u and v, which is connected in the tree.
Next line is a integer Q, representing the number of queries. (1 <= Q <= 10 5)
For next Q lines, each with an integer u, as the root of the subtree described above.
For each test case, the first line contains two integers N and K, as described above. ( 1<= N <= 10 5, 1 <= K <= N )
Then come N integers in the second line, they are the weights of vertice 1 to N. ( 0 <= weight <= 10 9 )
For next N-1 lines, each line contains two vertices u and v, which is connected in the tree.
Next line is a integer Q, representing the number of queries. (1 <= Q <= 10 5)
For next Q lines, each with an integer u, as the root of the subtree described above.
Output
For each test case, output "Case #X:" first, X is the test number. Then output Q lines, each with a number -- the answer to each query.
Seperate each test case with an empty line.
Seperate each test case with an empty line.
Sample Input
1 3 1 1 2 2 1 2 1 3 3 2 1 3
Sample Output
Case #1: 1 1 1 题意:静态问区间中出现次数为k的数字的个数。 分析:通过dfs序可以将树上的问题转化为区间问题,然后可以通过将操作离线按右端点排序用每次用树状数组更新答案,同样可以用可持久化线段树转换成在线问题。#include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<queue> #define INF 0x3f3f3f3f #define eps 1e-9 #define MOD 1000000007 #define MAXN 100005 using namespace std; typedef long long ll; int T,n,k,q,u,v,cnt,num,dfs_cnt,w[MAXN],fh[MAXN],rd[MAXN],cd[MAXN],rt[MAXN],b[MAXN],sta[MAXN],Next[MAXN],pre[MAXN],temp[MAXN],sum[MAXN]; vector <int> G[MAXN]; struct Tree { int ls,rs,lazy; }tr[MAXN*40]; void Build(int &node,int l,int r) { node = ++cnt; tr[node].lazy = 0; if(l == r) return; int mid = (l+r) >> 1; Build(tr[node].ls,l,mid); Build(tr[node].rs,mid+1,r); } void deal(int &node,int x,int y,int d,int l,int r) { tr[cnt+1] = tr[node]; node = ++cnt; if(x == l && y == r) { tr[node].lazy += d; return; } int mid = (l+r) >> 1; if(y <= mid) deal(tr[node].ls,x,y,d,l,mid); else if(x <= mid) { deal(tr[node].ls,x,mid,d,l,mid); deal(tr[node].rs,mid+1,y,d,mid+1,r); } else deal(tr[node].rs,x,y,d,mid+1,r); } int Find(int node,int x,int l,int r) { if(l == r) return tr[node].lazy; int mid = (l+r)>>1; if(x <= mid) return tr[node].lazy + Find(tr[node].ls,x,l,mid); else return tr[node].lazy + Find(tr[node].rs,x,mid+1,r); } void dfs(int u,int fa) { rd[u] = ++dfs_cnt; fh[dfs_cnt] = u; for(int v : G[u]) if(v != fa) dfs(v,u); cd[u] = dfs_cnt; } void Init() { dfs_cnt = cnt = 0; memset(rt,0,sizeof(rt)); memset(pre,0,sizeof(pre)); memset(sum,0,sizeof(sum)); memset(Next,0,sizeof(Next)); memset(temp,0,sizeof(temp)); for(int i = 1;i <= n;i++) G[i].clear(); } int main() { scanf("%d",&T); for(int t = 1;t <= T;t++) { Init(); if(t > 1) printf("\n"); printf("Case #%d:\n",t); scanf("%d%d",&n,&k); for(int i = 1;i <= n;i++) { scanf("%d",&w[i]); b[i] = w[i]; } sort(b+1,b+1+n); for(int i = 1;i <= n;i++) w[i] = lower_bound(b+1,b+1+n,w[i]) - b; for(int i = 1;i < n;i++) { scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } dfs(1,-1); Build(rt[0],1,n); for(int i = 1;i <= n;i++) { int color = w[fh[i]]; if(temp[color]) Next[temp[color]] = i; pre[i] = temp[color]; temp[color] = i; } for(int i = 1;i <= n;i++) { int color = w[fh[i]]; rt[i] = rt[i-1]; if(!sum[color]) sta[color] = i; sum[color]++; if(sum[color] == k) deal(rt[i],1,sta[color],1,1,n); else if(sum[color] > k) { deal(rt[i],pre[sta[color]]+1,sta[color],-1,1,n); deal(rt[i],sta[color]+1,Next[sta[color]],1,1,n); sta[color] = Next[sta[color]]; } } scanf("%d",&q); for(int i = 1;i <= q;i++) { scanf("%d",&num); printf("%d\n",Find(rt[cd[num]],rd[num],1,n)); } } }