hdu 4358
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4358
题解:先将树形结构转化成线性结构,这样问题就可以转化为求一个区间内,恰好出现K次的权值有多少种。利用树状数组记录K次的种数.

#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<vector> #define lowbit(x) (x)&(-x) using namespace std; const int maxn = 100005; struct nd{int next,v;}edge[maxn*2]; int head[maxn*2],sl[maxn][2],vis[maxn*2],sum[maxn*2],last[maxn*2],val[maxn*2],as[maxn*2],in[maxn*2]; int ecnt,idx,n,K; vector<int>path[maxn]; void add(int u,int v) { edge[ecnt].v = v; edge[ecnt].next = head[u]; head[u] = ecnt++; } void update(int x,int v){if(x)for(;x<=idx;x+=lowbit(x))sum[x]+=v;} int getsum(int x,int v){for(;x;x-=lowbit(x))v+=sum[x];return v;} int bitser(int x) { int l = 1,r = n,m; while(l < r){ m = (l + r) >> 1; if(as[m]>=x)r = m; else l = m + 1; }return l; } void getlist(int x) { sl[x][0] = ++idx; vis[idx] = x; for(int i = head[x]; ~i; i = edge[i].next) getlist(edge[i].v); sl[x][1] = ++idx; vis[idx] = -x; } void readin() { int i,u,v; scanf("%d %d",&n,&K); for(i = 1; i <= n; ++ i) {scanf("%d",as+i);val[i] = as[i];} sort(as+1,as+n+1); for(i = 1; i <= n; ++ i) val[i] = bitser(val[i]); memset(head,-1,sizeof(head)); memset(in,0,sizeof(in)); ecnt = 0; for(i = 1; i < n; ++ i){ scanf("%d %d",&u,&v); add(u,v); in[v]++; } idx = 0; getlist(1); } void processing() { int i,k,v; memset(in,0,sizeof(in)); memset(sum,0,sizeof(sum)); memset(last,0,sizeof(last)); for(i = 1; i <= n; ++ i){ path[i].clear(); path[i].push_back(0); } for(i = 1; i <= idx; ++ i)if(vis[i]>0){ k = vis[i]; v = val[k]; path[v].push_back(i); in[v]++; if(in[v]>=K){ if(in[v] > K){ update(path[v][in[v]-K-1]+1,-1); update(path[v][in[v]-K]+1,1); } update(path[v][in[v]-K]+1,1); update(path[v][in[v]-K+1]+1,-1); } }else{ k = -vis[i]; as[k] = getsum(sl[k][0],0); } } void query() { int m,k; scanf("%d",&m); while(m--){ scanf("%d",&k); printf("%d\n",as[k]); } } int main() { int T,cas=0; for(scanf("%d",&T);T--;){ if(cas)puts(""); printf("Case #%d:\n",++cas); readin(); processing(); query(); } return 0; }