败方树(输者树)的建立

给定一个整数数组,要求对数组中的元素构建败方树(数组相邻元素两两比较,从第一个元素开始)。之后修改数组中的元素,要求输出初始构建以及修改后得到的败方树的所有内部结点代表的整数(从左到右从上到下输出)

 

输入

第一行为数组的元素个数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

 

分析过程都在代码中做出了标注,代码如下:

#include<iostream>
#include<vector>
#include<map>

using namespace std;
class loserTree
{
   public:
       loserTree(int* thePlayers,int n);     //create the loser tree
       ~loserTree(){delete [] tree;delete [] temp;} //release resources

        void replay(int thePlayer,int value); //replay the game
        void output() const;
        int* theTree(){return tree;}        
   private:
       int* tree;     //place the loser in the game,but tree[0] is final winner
       int* player;   //the player to compete
       int* temp;    //place the winner to compete
       int numOfPlayer;  //the number of the player to compete

       int lowExt;  //2*(n-s),represent the number of the bottom,s=2^(log2(n-1))
                    //s represent the index of the far left of the bottom
       int offset;   //2*s-1

       int winner(int x,int y){return player[x]<=player[y]?x:y;}   //return the winner
       int loser(int x,int y){return player[x]>player[y]?x:y;}     //return the loser
       void play(int gamepoint,int leftPlayer,int rightPlayer);  //to comptete,if left<=right left win,else left lose
};
loserTree::loserTree(int* thePlayers,int n)
{
     tree=nullptr,temp=nullptr;
     if(n<2){return;}
     player=thePlayers;
     numOfPlayer=n;
     tree=new int[n];
     temp=new int[n];

     int i,s;
     for(s=1;2*s<=n-1;s*=2);
     lowExt=2*(n-s);     //when player begins from index 1,  lowExt=2*(n-s)   offset=2*s-1;
     offset=2*s-1;

    for(i=2;i<=lowExt;i+=2)
      {// players of the last layer compete
          play((i+offset)/2,i-1,i);
      }
   
     //deal with the special point
    if(n%2==1){  //the left player of game point is from tree[i]
          play(n/2,temp[n-1],lowExt+1);
          i=lowExt+3;
     }else{
          i=lowExt+2;
     }

    for(;i<=n;i+=2)
    { //players of the last but one layer compete
        play((i-lowExt+n-1)/2,i-1,i);
    }
    tree[0]=temp[1];    //record the winner int the lose tree
}
void loserTree::play(int p,int left,int right)
{
    tree[p]=loser(left,right);   //when p is even,the competition only one time 
    temp[p]=winner(left,right);  //why?p is even that means compete only occur int the last layer
                                  //ioslate that special point with lower point
   //this means the players all exists int the lose tree,continue upper until to the top
    while (p % 2 == 1&& p > 1)  //the index of the right player is always odd
	{
           tree[p/2]=loser(temp[p-1],temp[p]);   // loser
           temp[p/2]=winner(temp[p-1],temp[p]);   // winner

           p /= 2;    //continue unitl reach the root
	}
}
void loserTree::replay(int thePlayer,int newValue)
{
      int n=numOfPlayer;
      if(thePlayer<=0||thePlayer>n){
          cout<<"the parameter is error"<<endl;
          return;
      }
     player[thePlayer]=newValue;
   //get the left player and the right player
     int matchPoint,left,right;      //game point,left player,right player
     if(thePlayer<=lowExt){       //the player is on the bottom 
         matchPoint=(thePlayer+offset)/2; 
         left=2*matchPoint-offset;    // unify to the left player
         right=left+1;
     }else{   //the player is on the last but one
         matchPoint=(thePlayer-lowExt+n-1)/2;

         if(2*matchPoint==n-1){  //special gamepoint
             left=temp[2*matchPoint];
             right=thePlayer;
         }else{
             left=2*matchPoint-(n-1)+lowExt;
             right=left+1;
         }
     }

     //to compete
     if(thePlayer==tree[0]){//the player to replay is the previous winner!!!,ok,that's simple
           for(;matchPoint>=1;matchPoint/=2)
           {// and we note the left and right is not necessary,so the upper code can be simpler
             int loserTemp=loser(tree[matchPoint],thePlayer);
             temp[matchPoint]=winner(tree[matchPoint],thePlayer);
             tree[matchPoint]=loserTemp;
             thePlayer=temp[matchPoint];
           }
     }else{  //it's normal,but the competiton is a bit complex
         tree[matchPoint]=loser(left,right);  //first game
         temp[matchPoint]=winner(left,right);
         if(matchPoint==n-1&&n%2==1){   //second game,and it's special
            matchPoint/=2;
            tree[matchPoint]=loser(temp[n-1],lowExt+1);  //fisrt game
            temp[matchPoint]=winner(temp[n-1],lowExt+1);
          }
          matchPoint/=2;  //then all is back to normal,continue competing
          for(;matchPoint>=1;matchPoint/=2)
          {
            tree[matchPoint]=loser(temp[2*matchPoint],temp[2*matchPoint+1]);
            temp[matchPoint]=winner(temp[2*matchPoint],temp[2*matchPoint+1]);
          }
     }
   tree[0]=temp[1];  //place the new winner
}
void loserTree::output() const
{
     for(int i=0;i<numOfPlayer;i++)   //< not <=
     {cout<<player[tree[i]]<<" ";}
}

int main()
{ //int players[]={0,10,9,20,6,16,12,90,17};
     int n,m;
     cin>>n>>m;
     int* players=new int[n+1];  //the number of valid element is n
     for(int i=1;i<=n;i++)
      {
           cin>>players[i];
      }
     loserTree ltree(players,n);
     vector<pair<int,int>> vPair;
     int index,value;
     for(int i=1;i<=m;i++)
      {//record the input
          cin>>index>>value;
          pair<int,int>ptemp(index+1,value);
          vPair.push_back(ptemp);
      }

       ltree.output();//output the original result
       cout<<endl;
      for(int i=0;i<vPair.size();i++)
      {//output the results
          ltree.replay(vPair[i].first,vPair[i].second);
          ltree.output();
          cout<<endl;
      }
   delete [] players;
}

简化版如下

#include<iostream>
#include<vector>
#include<utility>
#include<cmath>
using namespace std;

class loserTree
{
public:
	loserTree(int* thePlayer, int num) {
		if (num<2) { return; }
		player = thePlayer;
		n = num;
		tree = new int[n];

		int s = log(n - 1) / log(2);
		s = pow(2, s);
		lowext = 2 * (n - s);
		offset = 2 * s - 1;
		int i = 0;
		for (i = 2; i <= lowext; i += 2) {
			play((i + offset) / 2, i - 1, i);
		}
		if (n % 2 == 1) {
			play(n / 2, tree[(n - 1) / 2], lowext + 1);
			i = lowext + 3;
		}
		else {
			i = lowext + 2;
		}
		for (; i <= n; i += 2) {
			play((i - lowext + n - 1) / 2, i - 1, i);
		}
	}
	~loserTree() { delete[] tree; }

	void replay(int k, int value) {
		player[k] = value;
		int root = k <= lowext ? (k + offset) / 2 : (n - 1 + k - lowext) / 2;
		pair<int, int> re;
		for (; root >= 1; root /= 2) {
			re = compete(tree[root],tree[0]);
			tree[root] = re.second;
			tree[0] = re.first;
		}

	}
	void output() const {
		for (int i = 0; i<n; i++){
			cout << player[tree[i]] << " ";
		}
	}

private:
	int* tree;
	int* player;
	int  n;

	int lowext;
	int offset;

	pair<int, int> compete(int x, int y) {
		pair<int, int>re;
		re.first = player[x] <= player[y] ? x : y;
		re.second = player[x]>player[y] ? x : y;
		return re;
	}
	void play(int p, int left, int right) {
		pair<int, int> re = compete(left, right);
		tree[p] = re.second;   //loser
		while (p % 2 == 1 && p>1) {
			re = compete(tree[p / 2], re.first);
			tree[p / 2] = re.second;
			p /= 2;
		}
		tree[p / 2] = re.first; //winner
	}
};
int main()
{
	int n, m;
	cin >> n >> m;
	int* players = new int[n + 1];
	for (int i = 1; i <= n; i++) {
		cin >> players[i];
	}
	loserTree ltree(players, n);
	ltree.output();
	cout << endl;
	int index, value;
	for (int i = 1; i <= m; i++) {
		cin >> index >> value;
		ltree.replay(index+1, value);
		ltree.output();
		cout << endl;
	}

	delete[] players;
	return 0;

}

 

  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值