[USACO17JAN]Promotion Counting
线段树合并。
正解好像不是线段树合并,但是出于练手的目的写了线段树合并。
大概就是对于左右子树,如果有一个为空,返回非空的,如果都不为空,就把这两个整合到一起就行了。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=100005;
int tot,ls[N<<5],rs[N<<5],siz[N<<5],n,p[N],head[N],ecnt,lsh[N],LSH,ans[N],rt[N];
struct Edge{int to,nxt;}e[N<<1];
void add(int bg,int ed){e[++ecnt].to=ed;e[ecnt].nxt=head[bg];head[bg]=ecnt;}
void pushup(int x) {siz[x]=siz[ls[x]]+siz[rs[x]];}
void update(int &k,int l,int r,int val) {
if(!k)k=++tot;int mid=l+r>>1;
if(l==r) {siz[k]++;return;}
if(val<=mid) update(ls[k],l,mid,val);
else update(rs[k],mid+1,r,val);
pushup(k);
}
int query(int ql,int qr,int l,int r,int cur) {
int mid=l+r>>1;
if(ql<=l&&r<=qr) return siz[cur];
int sum=0;
if(ql<=mid) sum+=query(ql,qr,l,mid,ls[cur]);
if(qr>mid) sum+=query(ql,qr,mid+1,r,rs[cur]);
return sum;
}
int merge(int u,int v) {
if(u*v==0) return u+v;
ls[u]=merge(ls[u],ls[v]);
rs[u]=merge(rs[u],rs[v]);
pushup(u);
return u;
}
void dfs(int x,int fa) {
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;
if(v==fa) continue;
dfs(v,x);
rt[x]=merge(rt[x],rt[v]);
}
ans[x]=query(p[x]+1,n,1,n,rt[x]);
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&p[i]),lsh[++LSH]=p[i];
sort(lsh+1,lsh+1+LSH);
int u=unique(lsh+1,lsh+1+LSH)-lsh-1;
for(int i=1;i<=n;i++) p[i]=lower_bound(lsh+1,lsh+1+u,p[i])-lsh;
for(int i=2,fa;i<=n;i++) scanf("%d",&fa),add(i,fa),add(fa,i);
for(int i=1;i<=n;i++) update(rt[i],1,n,p[i]);
dfs(1,0);for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
}
我是咸鱼。转载博客请征得博主同意Orz