51nod1297 管理二叉树
题目来源: HackerRank
基准时间限制:3 秒 空间限制:131072 KB 分值: 640
一个初始为空的二叉搜索树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
树 规律题 动态点分治
直接模拟建树妥妥被卡。
分析一波可以发现,将一个点x添加进树的时候,在所有已有点中找到x的前驱和后继,x要么是前驱的右儿子,要么是前驱的左儿子。
思考一下或者手玩一波会发现“前驱的右儿子”和“后继的左儿子“不会同时为空,所以要添加到哪里是确定的。
我们可以离线操作,先将树建好,之后按顺序每次添加一个点,统计它到所有已有点的距离。
剩下的部分显然是动态点分治模板题。
写完WA了一半点,旁边czy说:“想必没有开LL”
开了LL以后还有三个点WA,旁边czy说:“想必数组不够大”
开大了数组就AC辣
他真是个小天才!
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 #include<set> 7 #define LL long long 8 using namespace std; 9 const int INF=0x3f3f3f3f; 10 const int mxn=150010; 11 int read(){ 12 int x=0,f=1;char ch=getchar(); 13 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 struct edge{ 18 int v,nxt; 19 }e[mxn<<1]; 20 int hd[mxn],mct=0; 21 void add_edge(int u,int v){ 22 e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return; 23 } 24 void insert(int u,int v){ 25 add_edge(u,v);add_edge(v,u);return; 26 } 27 int sz[mxn],mc[mxn],rot,smm; 28 int dep[mxn],dis[mxn][23]; 29 int an[mxn][23]; 30 LL ans1[mxn],ans2[mxn],num[mxn]; 31 LL nowans; 32 bool vis[mxn]; 33 void DFS_sz(int u,int fa){ 34 sz[u]=mc[u]=1; 35 for(int i=hd[u];i;i=e[i].nxt){ 36 int v=e[i].v;;if(v==fa || vis[v])continue; 37 DFS_sz(v,u); 38 sz[u]+=sz[v]; 39 mc[u]=(sz[v]>mc[u])?sz[v]:mc[u]; 40 } 41 mc[u]=max(mc[u],smm-sz[u]); 42 if(mc[u]<mc[rot])rot=u; 43 return; 44 } 45 void calc(int u,int fa,int ance,int dist){ 46 an[u][++dep[u]]=ance; 47 dis[u][dep[u]]=dist; 48 for(int i=hd[u];i;i=e[i].nxt){ 49 int v=e[i].v; 50 if(v==fa || vis[v])continue; 51 calc(v,u,ance,dist+1); 52 } 53 return; 54 } 55 void solve(int x){ 56 vis[x]=1; 57 // printf("solve:%d\n",x); 58 calc(x,x,x,0);dep[x]--; 59 for(int i=hd[x];i;i=e[i].nxt){ 60 int v=e[i].v; 61 if(!vis[v]){ 62 smm=sz[v]; mc[rot=0]=INF; 63 DFS_sz(v,x); 64 solve(rot); 65 } 66 } 67 return; 68 } 69 void add(int u){ 70 LL tmp=ans1[u]; 71 for(int i=dep[u];i>1;i--){ 72 LL dist=dis[u][i-1]; 73 tmp+=ans1[an[u][i-1]]-ans2[an[u][i]]; 74 tmp+=dist*(num[an[u][i-1]]-num[an[u][i]]); 75 } 76 nowans+=tmp; 77 num[u]+=1; 78 for(int i=dep[u];i>1;i--){ 79 LL dist=dis[u][i-1]; 80 ans1[an[u][i-1]]+=dist*1; 81 ans2[an[u][i]]+=dist*1; 82 num[an[u][i-1]]+=1; 83 } 84 return; 85 } 86 // 87 int ch[mxn][2]; 88 //int st[mxn],top=0; 89 int n,x[mxn],M[mxn],U[mxn]; 90 set<int>st; 91 void init(){ 92 st.insert(x[1]);set<int>::iterator it,it2; 93 for(int i=2;i<=n;i++){ 94 st.insert(x[i]); 95 it=it2=st.lower_bound(x[i]); 96 if(it!=st.end()){it++;if(it!=st.end())U[i]=(*it);} 97 if(it2!=st.begin()){it2--; M[i]=(*it2);} 98 } 99 for(int i=2;i<=n;i++){ 100 if(!M[i] || ch[M[i]][1]){ 101 ch[U[i]][0]=x[i]; 102 insert(U[i],x[i]); 103 continue; 104 } 105 if(!U[i] || ch[U[i]][0]){ 106 ch[M[i]][1]=x[i]; 107 insert(M[i],x[i]); 108 } 109 } 110 return; 111 } 112 int main(){ 113 int i,j; 114 n=read(); 115 for(i=1;i<=n;i++)x[i]=read(); 116 init(); 117 smm=n; 118 mc[rot=0]=INF; 119 DFS_sz(1,0); 120 solve(rot); 121 for(i=1;i<=n;i++){ 122 an[i][++dep[i]]=i; 123 dis[i][dep[i]]=0; 124 } 125 for(i=1;i<=n;i++){ 126 add(x[i]); 127 printf("%lld\n",nowans); 128 } 129 return 0; 130 }
本文为博主原创文章,转载请注明出处。