一个初始为空的二叉搜索树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示例
8 4 7 3 1 8 2 6 5
Output示例
0 1 4 10 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;
}