[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]);
}
posted @ 2018-08-20 10:01  SWHsz  阅读(129)  评论(0编辑  收藏  举报