用顺序统计树(红黑树扩张)解决逆序对POJ1804

本文介绍了一种使用扩展的红黑树(增加了size属性)来解决逆序对问题的方法。在插入过程中,通过计算节点及其右子树的大小来动态更新逆序对数量。代码中实现了红黑树的插入、旋转和修复操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

扩张的红黑树,每个结点增加一个size属性。
解题思路:
按输入顺序,不断insert,在insert时,判断
当往下走(寻找要插入的位置)时,走到一个结点(设为A)的左子树时,z小于A和A右子树,且z出现在A和A右子树之后(对于输入数组来说),故z和A、z和A右子树的所有结点形成逆序对。
#include<cstdio>
#include<queue>
#include<iostream>
#include<algorithm>
//#include<windows.h>
using namespace std;
enum RBCOLOR{RED,BLACK};
class RBNODE{
public:
    int key;
    RBNODE* left;
    RBNODE* right;
    RBNODE* parent;
    RBCOLOR color;
    int size;

    RBNODE(int key){this->key=key;}
};
class RB{
public:
    RBNODE *root;
    RBNODE *nil;
    int inversion_count;

    RB(){nil=new RBNODE('#');root=nil;nil->color=BLACK;inversion_count=0;nil->size=0;}
    ~RB(){delete_tree(root);}
    void LEFT_ROTATE(RBNODE* x)
    {
        RBNODE* y=x->right;x->right=y->left;
        if(y->left!=nil) y->left->parent=x;
        y->left=x;
        if(x->parent==nil) root=y;
        else if(x==x->parent->left) x->parent->left=y;
        else x->parent->right=y;
        y->parent=x->parent;x->parent=y;
        y->size=x->size;
        x->size=x->left->size+x->right->size+1;
    }
    void RIGHT_ROTATE(RBNODE* y)
    {
        RBNODE* x=y->left;y->left=x->right;
        if(x->right!=nil) x->right->parent=y;
        x->right=y;
        if(y->parent==nil) root=x;
        else if(y->parent->left==y) y->parent->left=x;
        else y->parent->right=x;
        x->parent=y->parent;y->parent=x;
        x->size=y->size;
        y->size=y->left->size+y->right->size+1;
    }
    void RB_INSERT(RBNODE* z)
    {
        RBNODE* parent=nil;
        RBNODE* node=root;
        while(node!=nil){
            parent=node;parent->size++;
            if(z->key<node->key){
              inversion_count+=node->right->size+1;
              node=node->left;
            }
            else node=node->right;
        }
        //cout<<inversion_count<<endl;
        if(parent==nil) root=z;
        else if(z->key<parent->key) parent->left=z;
        else parent->right=z;
        z->parent=parent;z->color=RED;
        z->left=z->right=nil;z->size=1;

        RB_INSERT_FIXUP(z);
//        cout<<"node:"<<z->key<<endl;
//        preorder_traverse();
//        inorder_traverse();
//        postorder_traverse();

    }
    void RB_INSERT_FIXUP(RBNODE* z)
    {
        while(z->parent->color==RED){
            if(z->parent==z->parent->parent->left){
                RBNODE* uncle=z->parent->parent->right;
                if(uncle->color==RED){
                    z->parent->color=BLACK;//case 1
                    uncle->color=BLACK;//case 1
                    z->parent->parent->color=RED;//case 1
                    z=z->parent->parent;//case 1
                }
                else{
                    if(z==z->parent->right){
                        z=z->parent;LEFT_ROTATE(z);//case 2
                    }
                    z->parent->color=BLACK;//case 3
                    z->parent->parent->color=RED;//case 3
                    RIGHT_ROTATE(z->parent->parent);//case 3
                }
            }else{//same as "then" clause with right and left exchanged
                RBNODE* uncle=z->parent->parent->left;
                if(uncle->color==RED){
                    z->parent->color=BLACK;//case 1
                    uncle->color=BLACK;//case 1
                    z->parent->parent->color=RED;//case 1
                    z=z->parent->parent;//case 1
                }
                else{
                    if(z==z->parent->left){
                        z=z->parent;RIGHT_ROTATE(z);//case 2
                    }
                    z->parent->color=BLACK;//case 3
                    z->parent->parent->color=RED;//case 3
                    LEFT_ROTATE(z->parent->parent);//case 3
                }
            }
        }
        root->color=BLACK;
    }
    void delete_tree(RBNODE* node)
    {
        if(node!=nil){
            delete_tree(node->left);
            delete_tree(node->right);
            delete node;
        }
    }
//    void level_traverse()
//    {
//        queue<RBNODE*> Q;
//        if(root!=nil) Q.push(root);
//        cout<<Q.front()->key<<endl;
//        int height=TREE_HEIGHT(root)-1;
//        for(int i=0;i<=height;i++){//按层打印
//            print_space(1<<(height-i));//在一层的最前打印2^(height-i)个空格
//            int node_number=1<<i;//该层结点数
//            for(int j=0;j<node_number;j++){//打印第i层结点
//                RBNODE* node=Q.front();
//                if(node==nil){Q.push(nil);Q.push(nil);}
//                else{Q.push(node->left);Q.push(node->right);}
//                print_node(node);Q.pop();
//                print_space((1<<(height-i+1))-1);
//            }
//            putchar('\n');
//        }
//    }
//    void print_node(RBNODE* node)
//    {
//        if(node!=nil){
//            if(node->color==RED) color(12,0);
//            putchar(node->key);
//            color(8,0);
//        }
//        else putchar(' ');
//    }
//    void print_space(int num)
//    {
//        CONSOLE_SCREEN_BUFFER_INFO bInfo;
//        GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&bInfo);
//        COORD c=bInfo.dwCursorPosition;
//        while(num--) putchar(' ');
//    }
//    int TREE_HEIGHT(RBNODE* node)
//    {
//        if(node==nil) return 0;
//        else return max(TREE_HEIGHT(node->left),TREE_HEIGHT(node->right))+1;
//    }
//    void color(unsigned short int fore,unsigned short int back)
//    {
//        HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
//        SetConsoleTextAttribute(hOut,fore+back*16);
//    }

};


int main()
{
    //freopen("1.txt","r",stdin);
    int n;
    scanf("%d",&n);
    for(int j=1;j<=n;j++){
        RB* TREE=new RB();
        int key,m;scanf("%d",&m);
        for(int i=0;i<m;i++){
          scanf("%d",&key);
          TREE->RB_INSERT(new RBNODE(key));
        }
        //TREE->level_traverse();
        printf("Scenario #%d:\n%d\n",j,TREE->inversion_count);
        //cout<<"Scenario #"<<j<<":"<<endl<<TREE->inversion_count<<endl;
        if(j!=n) putchar('\n');
        delete TREE;//删除这句也可过,耗时少很多,不过耗比较多空间。时空权衡呗。反正都能过。
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值