連結:http://acm.hdu.edu.cn/showproblem.php?pid=4358
給你一棵樹,每個節點有一個點權,然後有一些詢問,求以某個點為根的子樹中有多少的數出現了k次
首先還是老方法,先轉換成線性序列,每個節點對應一個區間,然後離線操作,每個詢問都對應這一段區間,相當於詢問一段區間內出現k次的數的個數,將所有詢問的區間按照右端點排序,然後用線段樹來做,線段樹的第j個數代表[j,i]間出現k次的數的個數,記錄下每個數出現的所有位置,當這個數出現k次的時候【1->這個數第1次出現的位置】這段區間內的數到i之間出現k次的數都多了一個,具體見代碼
會爆棧,用到了類比棧,vector刪邊不好刪,於是也像樸素建鄰接表那樣開了一個head數組,記錄下當前訪問到了哪條邊
#include<cstdio>#include<vector>#include<stack>#include<algorithm>using namespace std;const int maxn = 100010;typedef vector<int> VI;int L[maxn],R[maxn];VI edge[maxn];int tot;int val[maxn];int num[maxn];stack<int> s;bool vis[maxn];int head[maxn];int n;void dfs(int root){ while(!s.empty()) s.pop(); fill(vis,vis+n+1,false); fill(head,head+n+1,0); s.push(root); while(!s.empty()) { int now = s.top(); if(!vis[now]) { L[now] = ++tot; num[tot]=val[now]; vis[now] = true; } bool flag=false; int sz=edge[now].size(); for(int i=head[now];i<sz;i++) { int v=edge[now][i]; if(!vis[v]) { flag = true; s.push(v); head[now]++; break; } } if(flag) continue; if(vis[now]) { R[now]=tot; s.pop(); } }}struct qq{ int v; int l,r,id; bool operator <(const qq& cmp)const{ return r < cmp.r; }}Q[maxn];int add[maxn<<2];void pushdown(int rt) { if(add[rt]) { add[rt<<1] += add[rt]; add[rt<<1|1] += add[rt]; add[rt] = 0; }}void build(int l,int r,int rt){ add[rt]=0; if(l==r) return ; int m=l+r>>1; build(l , m , rt<<1); build(m+1 , r , rt<<1|1);}void update(int L,int R,int val,int l,int r,int rt){ if(L <= l && r <= R) { add[rt]+=val; return ; } pushdown(rt); int m=l+r>>1; if(L <= m) update(L,R,val,l,m,rt<<1); if(R > m) update(L,R,val,m+1,r,rt<<1|1);}int query(int p,int l,int r,int rt){ if(l==r) return add[rt]; pushdown(rt); int m=l+r>>1; if(p <= m) return query(p,l,m,rt<<1); return query(p,m+1,r,rt<<1|1);}int san[maxn];VI pos[maxn];int ans[maxn];int main() { int t,ca=0,k,u,v,q; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&k); tot=0; for(int i=1;i<=n;i++) scanf("%d",&val[i]),san[i]=val[i],edge[i].clear(),pos[i].clear(); for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); edge[u].push_back(v); edge[v].push_back(u); } sort(san+1,san+n+1); int cnt=unique(san+1,san+n+1)-san-1; for(int i=1;i<=n;i++) val[i]=lower_bound(san+1,san+cnt+1,val[i])-san; dfs(1); scanf("%d",&q); for(int i=0;i<q;i++) { scanf("%d",&Q[i].v); Q[i].l=L[Q[i].v]; Q[i].r=R[Q[i].v]; Q[i].id=i; } sort(Q,Q+q); build(1,tot,1); int pt=0; for(int i=1;i<=tot;i++) { int value = num[i]; pos[value].push_back(i); int sz=pos[value].size(); if(sz >= k) { if(sz > k) { update(1,pos[value][sz-k-1],-1,1,tot,1); update(pos[value][sz-k-1]+1,pos[value][sz-k],1,1,tot,1); } else update(1,pos[value][sz-k],1,1,tot,1); } while(pt < q && Q[pt].r == i) { ans[Q[pt].id] = query(Q[pt].l,1,tot,1); pt++; } } if(ca) puts(""); printf("Case #%d:\n",++ca); for(int i=0;i<q;i++) printf("%d\n",ans[i]); } return 0;}