1. 程式人生 > 其它 >【題解】[USACO17JAN]Promotion Counting P

【題解】[USACO17JAN]Promotion Counting P

Problem

\(\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;
}