SCUT106 花式AC 主席树版本
题意:
给出一个点权树以$1$为根节点,求子树有几个节点的权值小于等于$k$。
题解:
主席树版本,先对树$dfs$求出第一次进入某节点的时间戳,然后同时处理出子树的节点数,然后求出的$dfs$序中某节点的时间戳后长度为该节点的子树的大小$-1$就是这个节点的子树对应的序列,在主席树上求个数即可。原理类似于求区间第k大,只不过是每棵主席树都保存了序列前$m(1 \leq m \leq n)$个数大小是$[1,n]$数的总个数,然后查询时查询区间中的$[1,k]$的数的个数即可。由于本题数值过大,因为权值是离散化的,所以输入的$k$也要离散化,找到小于等于k的第一个数。
AC代码:
#include <bits/stdc++.h> using namespace std; const int MAXN=100005; struct cheiftree { struct node { int l,r,sum; }; node tr[MAXN*20]; int rt[MAXN]; int cnt=0; void init() { cnt=0; } void build(int &rt,int l,int r) { rt=++cnt; tr[rt].sum=0; int m=(l+r)/2; if(l==r) return; build(tr[rt].l,l,m); build(tr[rt].r,m+1,r); } void update(int &rt,int l,int r,int k) { tr[++cnt]=tr[rt]; rt=cnt; ++tr[rt].sum; if(l==r) return; int m=(l+r)/2; if(k<=m) update(tr[rt].l,l,m,k); else update(tr[rt].r,m+1,r,k); } int query(int rl,int rr,int l,int r,int val) { if(l==r) return tr[rr].sum-tr[rl].sum; int m=(l+r)/2; if(val<=m) return query(tr[rl].l,tr[rr].l,l,m,val); else if(val>m) return tr[tr[rr].l].sum-tr[tr[rl].l].sum+query(tr[rl].r,tr[rr].r,m+1,r,val); } }; cheiftree tr; int in[MAXN],a[MAXN],b[MAXN],size[MAXN],vis[MAXN]; int cnt=0; vector<int>E[MAXN]; void print() { for(int i=1;i<=tr.cnt;++i) cout<<tr.tr[i].l<<" "<<tr.tr[i].r<<" "<<tr.tr[i].sum<<endl; } void dfs(int u) { in[u]=++cnt; size[u]=1; vis[cnt]=u; for(auto &i:E[u]) { dfs(i); size[u]+=size[i]; } } void init(int n) { cnt=0; for(int i=1;i<=n;++i) E[i].clear(); } int main() { int n,t,m; while(~scanf("%d%d",&n,&m)) { init(n); for(int i=1;i<n;++i) { scanf("%d",&t); E[t].push_back(i+1); } dfs(1); //for(int i=1;i<=cnt;++i) //cout<<in[i]<<" "<<size[i]<<" "<<vis[i]<<endl; for(int i=1;i<=n;++i) { scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+1+n); int nnew=unique(b+1,b+1+n)-b-1; tr.init(); tr.build(tr.rt[0],1,nnew); for(int i=1;i<=n;++i) { tr.rt[i]=tr.rt[i-1]; int pos=lower_bound(b+1,b+1+nnew,a[vis[i]])-b; tr.update(tr.rt[i],1,nnew,pos); } //print(); for(int i=0;i<m;++i) { scanf("%d%d",&n,&t); int k=upper_bound(b+1,b+1+nnew,t)-b-1; int l=tr.rt[in[n]-1],r=tr.rt[in[n]+size[n]-1]; printf("%d\n",tr.query(l,r,1,nnew,k)); } } return 0; }