0
点赞
收藏
分享

微信扫一扫

51nod 1297 管理二叉树



1297 管理二叉树



题目来源:  HackerRank


基准时间限制:3 秒 空间限制:131072 KB 分值: 640  难度:8级算法题


 收藏

 关注

一个初始为空的二叉搜索树T,以及1到N的一个排列P: {a1, a2, ..., aN}。我们向这个二叉搜索树T添加这些数,从a1开始, 接下来是 a2, ..., 以aN结束。在每一个添加操作后,输出T上每对节点之间的距离之和。


例如:4 7 3 1 8 2 6 5。最终的二叉树为:



       4


     /   \


    3      7   


  /      /   \


 1      6     8


  \    /


   2  5



节点两两之间的距离和 = 6+5+5+4+3+2+1+5+4+4+3+2+1+4+3+3+2+1+3+2+2+1+2+1+1+2+1+3 = 76


Input


第1行:1个数N。(1 <= N <= 100000)第2 - N + 1行:每行1个数,对应排列的元素。(1 <= ai <= N)


Output


输出共N行,每行1个数,对应添加当前元素后,每对节点之间的距离之和。


Input示例


8473 1 8 2 6 5


Output示例


01410 20 35 52 76



李陶冶  (题目提供者)



【分析】

动态点分治

预处理出来各个节点与各层分治中心的距离等信息,按时间顺序逐个插入点统计答案。




【代码】

//51nod 1297 管理二叉树 
#include<bits/stdc++.h>
#define inf 1e6
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
const int mxn=150005;
set <int> s;
bool vis[mxn];
ll ans,tmp;
int n,m,T,cnt,tot,root;
int head[mxn],ch[mxn][2];
ll ans1[mxn],ans2[mxn],num[mxn];
int a[mxn],dep[mxn],pre[mxn],nxt[mxn];
int anc[mxn][22],dis[mxn][22],mx[mxn],sz[mxn];
struct edge {int to,next;} f[mxn<<1];
inline void add(int u,int v)
{
	f[++cnt].to=v,f[cnt].next=head[u],head[u]=cnt;
	f[++cnt].to=u,f[cnt].next=head[v],head[v]=cnt;
}
inline void dfs_size(int u,int fa)
{
	sz[u]=1,mx[u]=0;
	for(int i=head[u];i;i=f[i].next)
	{
		int v=f[i].to;
		if(v==fa || vis[v]) continue;
		dfs_size(v,u);
		sz[u]+=sz[v];
		mx[u]=max(mx[u],sz[v]);
	}
	mx[u]=max(mx[u],tot-sz[u]);
	if(mx[u]<mx[root]) root=u;
}
inline void dfs_dis(int u,int fa,int Anc,ll Dis)
{
	dep[u]++;
	anc[u][dep[u]]=Anc;
	dis[u][dep[u]]=Dis;
	for(int i=head[u];i;i=f[i].next)
	{
		int v=f[i].to;
		if(v==fa || vis[v]) continue;
		dfs_dis(v,u,Anc,Dis+1);
	}
}
inline void dfs(int u)
{
	mx[root=0]=inf;
	dfs_size(u,0);
	dfs_dis(root,root,root,0);
	dep[root]--,vis[root]=1;
	for(int i=head[root];i;i=f[i].next)
	{
		int v=f[i].to;
		if(vis[v]) continue;
		dfs_size(v,0);
	    tot=sz[v],dfs(v);
	}
}
inline void solve(int u)
{
	tmp=ans1[u];
	for(int i=dep[u];i>1;i--)
	{
		ll Dis=dis[u][i-1];
		tmp+=ans1[anc[u][i-1]]-ans2[anc[u][i]];
		tmp+=Dis*(num[anc[u][i-1]]-num[anc[u][i]]);
	}
	ans+=tmp,num[u]++;
	for(int i=dep[u];i>1;i--)
	{
		ll Dis=dis[u][i-1];
		ans1[anc[u][i-1]]+=Dis;
		ans2[anc[u][i]]+=Dis;
		num[anc[u][i-1]]++;
	}
	printf("%lld\n",ans);
}
inline void build()
{
	set <int>::iterator pr,nt;
	s.insert(a[1]);
	fo(i,2,n)
	{
		s.insert(a[i]);
		pr=nt=s.lower_bound(a[i]);
		if(nt!=s.end())
		{
			nt++;
			if(nt!=s.end())
			  nxt[a[i]]=(*nt);
		}
		if(pr!=s.begin())
		  pr--,pre[a[i]]=(*pr);
	}
	fo(i,2,n)
	{
		int u=a[i];
		if(!pre[u] || ch[pre[u]][1])
		{
			ch[nxt[u]][0]=u;
			add(nxt[u],u);
//			printf("connect=[%d,%d]\n",nxt[u],u);
			continue;
		}
		if(!nxt[u] || ch[nxt[u]][0])
		{
			ch[pre[u]][1]=u;
			add(pre[u],u);
//			printf("connect=[%d,%d]\n",pre[u],u);
		}
	}
}
int main()
{
	scanf("%d",&n);
	fo(i,1,n)
	  scanf("%d",&a[i]);
	build();
	tot=n,dfs(1);
	fo(i,1,n) anc[i][++dep[i]]=i;
	fo(i,1,n) solve(a[i]);
	return 0;
}



举报

相关推荐

0 条评论