1. 程式人生 > 實用技巧 >[USACO17JAN]Promotion Counting P 主席樹

[USACO17JAN]Promotion Counting P 主席樹

洛谷P3605

首先$dfs$一遍,記錄每個節點的$dfs$序和其子樹大小。

$p[i]$經離散化處理後按照$dfs$序的順序建立主席樹,每個節點的求解即為其子樹內$p$值小於該節點的節點數。

主席數差分查詢即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m,x,a[maxn],b[maxn],T[maxn];
int sum[maxn<<5],L[maxn<<5],R[maxn<<5];
int cnt,head[maxn],siz[maxn],pos[maxn],rk[maxn],tot;
struct Edge{ int to,next; }e[maxn]; void add(int u,int v) { e[++cnt].to=v; e[cnt].next=head[u]; head[u]=cnt; } void dfs(int u) { siz[u]=1; pos[u]=++tot; rk[tot]=u; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; dfs(v); siz[u]+=siz[v]; } }
int build(int l,int r) { int rt=++tot; if(l<r) { int mid=l+r>>1; L[rt]=build(l,mid),R[rt]=build(mid+1,r); } return rt; } int update(int pre,int l,int r,int pos) { int rt=++tot; L[rt]=L[pre],R[rt]=R[pre],sum[rt]=sum[pre]+1; if(l<r) { int
mid=l+r>>1; if(pos<=mid) L[rt]=update(L[pre],l,mid,pos); else R[rt]=update(R[pre],mid+1,r,pos); } return rt; } int query(int u,int v,int l,int r,int L_,int R_) { if(L_<=l&&R_>=r) return sum[v]-sum[u]; int mid=l+r>>1,res=0; if(L_<=mid) res+=query(L[u],L[v],l,mid,L_,R_); if(R_>mid) res+=query(R[u],R[v],mid+1,r,L_,R_); return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1; for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+n,a[i])-b; for(int i=2;i<=n;++i) scanf("%d",&x),add(x,i); dfs(1); tot=0; T[0]=build(1,m); for(int i=1;i<=n;++i) T[i]=update(T[i-1],1,m,a[rk[i]]); for(int i=1;i<=n;++i) printf("%d\n",query(T[pos[i]],T[pos[i]+siz[i]-1],1,m,a[i]+1,m)); return 0; }
View Code