P3605 [USACO17JAN]Promotion Counting P

原题链接
考察:树状数组+离散化
思路:
  很明显先离散化能力值.然后建边开始dfs树.
  比较难想的是如何求每个点比它能力高的子结点数量(对本蒟蒻而言)
  首先确定搜索顺序.先遍历子结点,然后再单点加入自己的权值.深度深的子节点可能会被深度浅的父节点用到更新,因此不能删除树状数组在子节点的存储的值.考虑先存储搜索子节点前的ans,在计算加入子节点后的ans.最后相减就是能力值高的子节点的个数.

#include <iostream> 
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 100010;
int n,a[N],tr[N],h[N],idx,ans[N];
vector<int> A;
struct Road{
	int fr,to,ne;
}road[N];
int get(int x)
{
	return lower_bound(A.begin(),A.end(),x)-A.begin()+1;
}
void adds(int a,int b)
{
	road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
}
int lowbit(int x)
{
	return x&-x;
}
int ask(int x)
{
	int ans = 0;
	for(int i=x;i;i-=lowbit(i)) ans+=tr[i];
	return ans;
}
void add(int k,int x)
{
	for(int i=k;i<=n;i+=lowbit(i)) tr[i]+=x;
}
void dfs(int u)
{
	int sc = get(a[u]);
	for(int i=h[u];~i;i=road[i].ne)
	{
		int v = road[i].to;
		ans[u]-=ask(n)-ask(sc);
		dfs(v);
		ans[u]+=ask(n)-ask(sc);
	}
	add(sc,1);
} 
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),A.push_back(a[i]);
	sort(A.begin(),A.end());
	memset(h,-1,sizeof h);
	for(int i=2;i<=n;i++)
	{
		int x; scanf("%d",&x);
		adds(x,i);
	}
	dfs(1);
	for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
	return 0;
}
posted @ 2021-05-15 20:32  acmloser  阅读(48)  评论(0编辑  收藏  举报