问题描述
给定一个整数数组,要求对数组中的元素构建败方树(数组相邻元素两两比较,从第一个元素开始)。之后修改数组中的元素,要求输出初始构建以及修改后得到的败方树的所有内部结点代表的整数(从左到右从上到下输出)
输入
第一行为数组的元素个数n和修改的次数m。
第二行为n个整数,即数组的元素。
接下来m行代表m次修改操作,每次操作修改数组中的一个元素,每一行包括两个整数,第一个为被修改元素在数组中的标号,第二个为修改之后的元素值。
输出
输出m+1行。
第一行为初始构建的败方树的所有内部结点代表的整数(按照树的结点从左到右从上到下的顺序输出)
接下来m行为接下来m次修改后得到的败方树的所有内部结点代表的整数(按照树的结点从左到右从上到下的顺序输出)
样例输入
8 1
10 9 20 6 16 12 90 17
3 15
样例输出
6 12 9 17 10 20 16 90
9 12 15 17 10 20 16 90
该题总体思路比较直观,就是模拟创建败者树的过程
总共就是初始建树和修改两个步骤
由于在败者树当中想要建立上一层的根节点需要知道赢者,而找到赢者需要回溯底层节点
观察到有的博客的建树思路是在每一次建立一个节点都向上一直更新到根节点(这样就不需要去做向下回溯寻找赢者的步骤了)
但是这样子建树第一遍是不完备的(受到顺序的影响),所以需要再做一遍
如下的代码思路比较直观,寻找赢者节点是直接使用的递归
POJ上的测试数据并不大,基本上不管使用什么思路只要是正确的应该不会存在超时或者爆栈 的问题。
整体代码由于是利用数组指针对败者树进行模拟,所以指针位置的操作比较繁琐,略显复杂,使部分代码不是很直观
#include<iostream>
using namespace std;
int A[1001];//将数组设为全局变量更有利于操作
int n,m;//同理设为全局变量
class Loser_tree{//创建败者树类,所有函数均在类中定义
public:
int len;//败者树数组的长度
int Max_N;//树的最底层元素的个数
int floor;//败者树的层数(除去赢者节点Tree_Array[0])
int *Tree_Array;//败者树数组指针
void Build(int );//初始建树函数
Loser_tree(int );//构造函数
int Vers(int pos);//寻找赢者(利用递归从当前根节点向下)
void ReBuild(int ,int );//修改败者树之后的重建
};
Loser_tree::Loser_tree(int n){
len=0;
floor=0;
Max_N=n/2;
if(n%2)++Max_N;//根据奇偶确定败者树最底层元素个数
for(int s=Max_N;s>=1;s/=2) ++floor,len+=s;//确定层数和数组长度
Tree_Array=new int[len+1];//
Build(n); //建树
}
void Loser_tree::Build(int n){
int father;
int l=n%2 ? n-1:n;//
for(int i=0,j=1;i<l;i+=2,++j){//先将最底层建立
father=len-Max_N+j;
Tree_Array[father]=A[i]>A[i+1] ? i:i+1;
}
if(n%2) Tree_Array[len]=A[n-1];//若为奇数则树最后节点补充
int sum=len-Max_N;
int a,b;
for(int s=1,j=2;s<floor;++s,j*=2){//从最底层逐层向上
sum-=Max_N/j;
for(father=sum+1;father<=sum+Max_N/j;++father){
a=Vers(2*father);//
b=Vers(2*father+1);//寻找赢者
Tree_Array[father]=A[a]>A[b] ? a:b;
}
}
Tree_Array[0]=Vers(1);
}
int Loser_tree::Vers(int pos){
if(pos>len-Max_N){//若到达最底层
if(Tree_Array[pos]==n-1&&Tree_Array[pos]%2==0) return n-1;
else return Tree_Array[pos]%2 ? Tree_Array[pos]-1 :Tree_Array[pos]+1;
}
else {//若不在最底层则向下递归
int a,b;
a=Vers(2*pos);
b=Vers(2*pos+1);
return A[a]<A[b]? a:b;
}
}
void Loser_tree::ReBuild(int pos,int val){//重建
int a=pos%2 ? pos-1:pos;
int b=pos%2 ? pos:pos+1;
int father=len-Max_N+(pos+2)/2;
Tree_Array[father]=A[a]>A[b] ? a:b;
father/=2;
while(father>=1){
a=Vers(2*father);
b=Vers(2*father+1);
Tree_Array[father]=A[a]>A[b] ? a:b;
father/=2;
}
// cout<<endl;
Tree_Array[0]=Vers(1);
}
int main(){
cin>>n>>m;
for(int i=0;i<n;++i)cin>>A[i];
Loser_tree Tree(n);
int len=Tree.len;
// for(int i=0;i<n;++i) cout<<Tree.Tree_Array[i]<<" ";
// cout<<endl;
for(int i=0;i<=len;++i) cout<<A[Tree.Tree_Array[i]]<<" ";
int pos,val;
for(int i=0;i<m;++i){
cout<<endl;
cin>>pos>>val;
A[pos]=val;
// for(int i=0;i<n;++i)cout<<A[i]<<" ";
// cout<<endl;
Tree.ReBuild(pos,val);
// for(int i=0;i<=len;++i) cout<<Tree.Tree_Array[i]<<" ";
// cout<<endl;
for(int i=0;i<=len;++i) cout<<A[Tree.Tree_Array[i]]<<" ";
}
}