题目:http://acm.hdu.edu.cn/showproblem.php?pid=4358
题解:先将树形结构转化成线性结构,这样问题就可以转化为求一个区间内,恰好出现K次的权值有多少种。利用树状数组记录K次的种数(还要用到栈外挂。。。)
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <cstring> #include <map> #include <vector> #include <algorithm> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; const int N = 100010; struct node{ int x, y, id; bool operator < (const node& a)const{ return y < a.y; } }qn[N]; int s[N], n, k, cnt; int e, r, he[N], w[N], val[N]; int ev[N*2], nxt[N*2]; int pre[N], ans[N]; int le[N], ri[N]; vector<int>pl[N]; map<int,int>mp; int lowbit(int a){ return a&(-a); } void insert(int a, int v){ while (a<=n){ s[a] += v; a += lowbit(a); } } int query(int a){ int res = 0; while (a){ res += s[a]; a -= lowbit(a); } return res; } void init(){ cnt = e = r = 0; clr(he, -1); clr(s,0); mp.clear(); } void add(int u, int v){ ev[e]=v, nxt[e]=he[u], he[u]=e++; } void dfs(int u, int fa){ le[u]=ri[u]=++r; val[r]=w[u]; for (int i=he[u]; i!=-1; i=nxt[i]){ if (ev[i]==fa) continue; dfs(ev[i], u); ri[u]=ri[ev[i]]; } } int main() { //freopen("D:/a.txt", "r", stdin); int T, q, cas=1; scanf("%d", &T); while (T--){ scanf("%d%d", &n, &k); init(); for (int i=1; i<=n; i++){ scanf("%d", &w[i]); if (!mp.count(w[i])){ mp[w[i]]=++cnt; pl[cnt].clear(); pl[cnt].push_back(0); } w[i]=mp[w[i]]; } for (int i=1; i<n; i++){ int u, v; scanf("%d%d", &u, &v); add(u, v), add(v, u); } dfs(1,1); scanf("%d", &q); for (int i=1; i<=q; i++){ int a; scanf("%d", &a); qn[i].x = le[a]; qn[i].y = ri[a]; qn[i].id = i; } sort(qn+1, qn+1+q); int t=1; for (int i=1; i<=n; i++){ int v = val[i]; pl[v].push_back(i); int g = pl[v].size()-1; if (g >= k){ if (g > k){ insert(pl[v][g-k-1]+1,-1); insert(pl[v][g-k]+1,1); } insert(pl[v][g-k]+1, 1); insert(pl[v][g-k+1]+1, -1); } while (qn[t].y==i){ ans[qn[t].id]=query(qn[t].x); t++; } } if (cas>1) puts(""); printf("Case #%d:\n", cas++); for (int i=1; i<=q; i++) printf("%d\n", ans[i]); } return 0; }