【題解】[USACO17JAN]Promotion Counting P
阿新 • • 發佈:2021-06-28
\(\text{Solution:}\)
題目求的就是一棵子樹中大於根節點權值的節點數。
這東西一看就很權值線段樹。
然後發現這東西又很線段樹合併。
考慮對每一個點維護一棵權值線段樹。這樣,我們將子樹的資訊合併到根的權值樹上,就可以做到 \(n\log n\) 合併資訊了。
然後對每個節點進行查詢即可。權值樹上維護一下區間和即可。由於空間問題要動態開點。
線段樹合併的空間複雜度是 \(O(n\log n)\) 的,又有一個約為 \(2\) 的常數(從某處看到的)(這是動態開點線段樹合併的複雜度)
所以開到 \(3.2\cdot 10^6\) 就可以了。
懶得思考怎麼直接求,實際上可以用差分的思想,更新完一棵子樹後,用更新前的資訊減去更新後的資訊即可。這樣用樹狀陣列也可以解決問題。
就當練習一下線段樹合併了。
#include<bits/stdc++.h> using namespace std; const int MAXN=3.2e6+10; const int N=2e5+10; int head[MAXN],tot,cnt,n,m; int ls[MAXN],rs[MAXN],ans[MAXN]; int dep[MAXN],pa[MAXN],siz[MAXN]; int b[MAXN],bcnt,blen; int v[MAXN],val[MAXN]; struct E{int nxt,to;}e[MAXN]; inline void add(int x,int y){e[++tot]=(E){head[x],y};head[x]=tot;} int rt[MAXN],sum[MAXN]; inline int getpos(int v){return lower_bound(b+1,b+blen+1,v)-b;} void dfs(int x,int fa){ dep[x]=dep[fa]+1; siz[x]=1; for(int i=head[x];i;i=e[i].nxt){ int j=e[i].to; if(j==fa)continue; dfs(j,x);siz[x]+=siz[j]; } } inline void pushup(int x){sum[x]=sum[ls[x]]+sum[rs[x]];} int change(int x,int l,int r,int pos,int v){ if(!x)x=++cnt; if(l==r){ sum[x]+=v; return x; } int mid=(l+r)>>1; if(pos<=mid)ls[x]=change(ls[x],l,mid,pos,v); else rs[x]=change(rs[x],mid+1,r,pos,v); pushup(x);return x; } int merge(int x,int y,int l,int r){ if(!x||!y)return x+y; if(l==r){ sum[x]+=sum[y]; return x; } int mid=(l+r)>>1; ls[x]=merge(ls[x],ls[y],l,mid); rs[x]=merge(rs[x],rs[y],mid+1,r); pushup(x);return x; } int query(int x,int l,int r,int ql,int qr){ if(l>=ql&&r<=qr)return sum[x]; int mid=(l+r)>>1,ans=0; if(ql<=mid)ans+=query(ls[x],l,mid,ql,qr); if(mid<qr)ans+=query(rs[x],mid+1,r,ql,qr); return ans; } void DFS(int x){ for(int i=head[x];i;i=e[i].nxt){ int j=e[i].to; if(j==pa[x])continue; DFS(j); rt[x]=merge(rt[x],rt[j],1,N); } ans[x]=query(rt[x],1,N,val[x]+1,N); } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d",&v[i]); for(int i=1;i<=n;++i)b[++bcnt]=v[i]; sort(b+1,b+bcnt+1); blen=unique(b+1,b+bcnt+1)-b-1; for(int i=1;i<=n;++i){ int pos=getpos(v[i]); val[i]=pos; } for(int i=1;i<=n;++i)rt[i]=change(rt[i],1,N,val[i],1); for(int i=2;i<=n;++i){ int x; scanf("%d",&x); add(x,i);pa[i]=x; } dfs(1,0); DFS(1); for(int i=1;i<=n;++i)printf("%d\n",ans[i]); return 0; }