splay树


问题 A: Splay —— Ver.I
问题 B: 宠物收养所(Splay —— 前驱后继操作)

问题 A: Splay —— Ver.I

题目描述

在这里插入图片描述

输入

第一行包含一个整数n,表示初始序列的长度。 以下n行每行包含一个整数,描述初始的序列。 接下来一行包含一个整数n,表示插入操作的数目。 以下m行每行描述一个操作。

接下来一行包含一个整数q,表示查询和删除操作的总数目,以下q行描述一个操作

输出

对于所有操作,输出正确的答案。

样例输入

5
1 2 3 4 5
3
ADD 9
ADD 10
ADD 199
5
QUERY 1
QUERY 3
DELETE 1
DELETE 3
QUERY 3

样例输出

the number is good
the number is good
2 3 4 5 9 10 199
2 4 5 9 10 199
the number is bad

代码1

#include <cstdio>
#include<iostream>
#include<string>
using namespace std;

const int N = 100005;
int rt, tot, fa[N], ch[N][2], val[N], cnt[N], sz[N];

class tree
{
    
    
public:
    void maintain(int x){
    
    
        sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + cnt[x]; 
    }

    bool get(int x){
    
     
        return x == ch[fa[x]][1]; 
    }

    void clear(int x){
    
    
        ch[x][0] = ch[x][1] = fa[x] = val[x] = sz[x] = cnt[x] = 0;
    }
    void rotate(int x){
    
    
        int y = fa[x], z = fa[y], chk = get(x);
        ch[y][chk] = ch[x][chk ^ 1];
        fa[ch[x][chk ^ 1]] = y;
        ch[x][chk ^ 1] = y;
        fa[y] = x;
        fa[x] = z;
        if (z) ch[z][y == ch[z][1]] = x;
        maintain(x);
        maintain(y);
    }
    void splay(int x){
    
    
        for (int f = fa[x]; f = fa[x], f; rotate(x))
        if (fa[f]) rotate(get(x) == get(f) ? f : x);
        rt = x;
    }
    void insert(int k){
    
    
        if (!rt) {
    
    
            val[++tot] = k;
            cnt[tot]++;
            rt = tot;
            maintain(rt);
            return;
        }
        int cnr = rt, f = 0;
        while (1) {
    
    
            if (val[cnr] == k){
    
    
                cnt[cnr]++;
                maintain(cnr);
                maintain(f);
                splay(cnr);
                break;
            }
            f = cnr;
            cnr = ch[cnr][val[cnr] < k];
            if (!cnr) {
    
    
                val[++tot] = k;
                cnt[tot]++;
                fa[tot] = f;
                ch[f][val[f] < k] = tot;
                maintain(tot);
                maintain(f);
                splay(tot);
                break;
            }
        }
    }
    int rk(int k) {
    
    
        int res = 0, cnr = rt;
        while (1) {
    
    
            if (k < val[cnr]) {
    
    
                cnr = ch[cnr][0];
            } else {
    
    
                res += sz[ch[cnr][0]];
                if (k == val[cnr]) {
    
    
                splay(cnr);
                return res + 1;
                }
                res += cnt[cnr];
                cnr = ch[cnr][1];
            }
        }
    }
    int kth(int k) {
    
    
        int cnr = rt;
        while (1) {
    
    
            if (ch[cnr][0] && k <= sz[ch[cnr][0]]) {
    
    
                cnr = ch[cnr][0];
            } else {
    
    
                k -= cnt[cnr] + sz[ch[cnr][0]];
                if (k <= 0) {
    
    
                splay(cnr);
                return val[cnr];
                }
                cnr = ch[cnr][1];
            }
        }
    }
    int pre() {
    
    
        int cnr = ch[rt][0];
        while (ch[cnr][1]) cnr = ch[cnr][1];
        splay(cnr);
        return cnr;
    }
    int next() {
    
    
        int cnr = ch[rt][1];
        while (ch[cnr][0]) cnr = ch[cnr][0];
        splay(cnr);
        return cnr;
    }
    void del(int k) {
    
    
        rk(k);
        if (cnt[rt] > 1) {
    
    
            cnt[rt]--;
            maintain(rt);
            return;
        }
        if (!ch[rt][0] && !ch[rt][1]) {
    
    
            clear(rt);
            rt = 0;
            return;
        }
        if (!ch[rt][0]) {
    
    
            int cnr = rt;
            rt = ch[rt][1];
            fa[rt] = 0;
            clear(cnr);
            return;
        }
        if (!ch[rt][1]) {
    
    
            int cnr = rt;
            rt = ch[rt][0];
            fa[rt] = 0;
            clear(cnr);
            return;
        }
        int cnr = rt;
        int x = pre();
        fa[ch[cnr][1]] = x;
        ch[x][1] = ch[cnr][1];
        clear(cnr);
        maintain(rt);
    }
};

int main() 
{
    
    
    tree task;
    int n,x;
    cin >> n;
    while(n--){
    
    
        int temp;
        cin >> temp;
        task.insert(temp);
    }
    cin >> n;
    while(n--){
    
    
        string str;
        int temp;
        cin >> str >> temp;
        task.insert(temp);
    }
    cin >> n;
    while(n--){
    
    
        string str;
        int temp;
        cin >> str >> temp;
        if(str.compare("QUERY")==0){
    
    
            if()cout << "the number is bad"<<endl;
            else cout << "the number is good" << endl;
        }else if(str.compare("DELETE")==0){
    
    
            task.del(temp);
        }
    }
  return 0;
}

代码2

#include<iostream>
#include<string>
using namespace std;

class node
{
    
    
public:
    int value;
    node *left,*right,*parent;
    node(){
    
    
        value=0;
        left=NULL,right=NULL,parent=NULL;
    }
    node(int p){
    
    
        value=p;
        left=NULL,right=NULL,parent=NULL;
    }
};

class tree
{
    
    
public:
    node* root;//树根
    int sl,sr,srr,sll,srl,slr;
    tree(){
    
    
        root=NULL;
        sl=sr=srr=sll=srl=slr=0;
    }
    node* find_return(int value1,node* p1){
    
    //寻找value1,返回其指针
        if(!p1)return NULL;//注意p不能为空????????????
        if(p1->value==value1)return p1;
        else if(value1>p1->value)return find_return(value1,p1->right);
        else return find_return(value1,p1->left);
        //return NULL;//找不到value1
    }
    node* find_return_splay(int value1,node* p1){
    
    //寻找value1,返回其指针
        if(!p1)return NULL;//注意p不能为空????????????
        if(p1->value==value1){
    
    splay(p1);return p1;}
        else if(value1>p1->value)return find_return_splay(value1,p1->right);
        else return find_return_splay(value1,p1->left);
        //return NULL;//找不到value1
    }
    void insert(int value2,node* &p2){
    
    //插入value2
        //先不管相等的情况
        if(!p2){
    
    
            p2=new node(value2);
            return;
        }
        if(value2<p2->value){
    
    
            if(!p2->left){
    
    
                node* subnode=new node(value2);
                p2->left=subnode;
                subnode->parent=p2;
                splay(subnode);//翻转节点并return
            }else insert(value2,p2->left);
        }else{
    
    
            if(!p2->right){
    
    
                node* subnode=new node(value2);
                p2->right=subnode;
                subnode->parent=p2;
                splay(subnode);
            }else insert(value2,p2->right);
        }   
    }
    node* find_min(node* p){
    
    
        while(p->left)p=p->left;
        return p;
    }
    void del(int value3){
    
    
        node* target=find_return(value3,root);
        if(!target){
    
    //没找到
            cout << "Failed" << endl;
            return;
        }
        splay(target);//将待删除的节点移到root
        if(!target->right){
    
    //右子树为空
            root=target->left;
            delete target;
        }else{
    
    
            node* right_min=find_min(root->right);//返回后继节点的指针
            root->value=right_min->value;//让right_min来当root
            
            if(right_min->parent->left==right_min){
    
    //他在父节点的左边
                if(right_min->right){
    
    //如果他有右子树
                    right_min->right->parent=right_min->parent;
                    right_min->parent->left=right_min->right;
                }else{
    
    
                    right_min->parent->left=NULL;
                }
            }else if(right_min->parent->right==right_min){
    
    //他在父节点的右边
                if(right_min->right){
    
    //如果他有右子树
                    right_min->right->parent=right_min->parent;
                    right_min->parent->right=right_min->right;
                }else{
    
    
                    right_min->parent->right=NULL;
                }
            }
            delete right_min;
        }
        print(root);
        cout << endl;
    }
    void print(node* p){
    
    
        if(!p)return;
        print(p->left);
        if(p)cout << p->value << ' ';
        print(p->right);
    }
    void splay(node* p3){
    
    //将p3所指的节点翻转至root
        //if(!p3->parent){root=p3;return;}//新根
        if(p3==root){
    
    //如果p3等于根节点
            return;
        }
        else if(p3==root->left){
    
    //p3为根节点的左孩子
            root=R(p3);
        }
        else if(p3==root->right){
    
    //p3为根节点的右孩子
            root=L(p3);
        }
        else{
    
    
            if(p3->parent->left==p3&&p3->parent->parent->left==p3->parent){
    
    
                RR(p3);
            }
            else if(p3->parent->right==p3&&p3->parent->parent->right==p3->parent){
    
    
                LL(p3);
            }
            else if(p3->parent->left==p3&&p3->parent->parent->right==p3->parent){
    
    
                RL(p3);
            }
            else if(p3->parent->right==p3&&p3->parent->parent->left==p3->parent){
    
    
                LR(p3);
            }
        }
        splay(p3);//知道p3到达root才return
    }
    node* L(node* p){
    
    
        sl++;
        if(!p)return NULL;
        node* parent=p->parent;
        node* grandparent=parent->parent;
        parent->right=p->left;
        if(p->left)p->left->parent=parent;
        p->left=parent;
        parent->parent=p;
        p->parent=grandparent;//如果grandparent为空
        if(grandparent){
    
    
            if(grandparent->left==parent)
                grandparent->left=p;
            else grandparent->right=p;
        }else{
    
    //回去之后splay会帮你更新root
            root=p;
        }
        return p;
    }
    node* R(node* pt){
    
    
        sr++;
        if(!pt)return NULL;
        node* parent=pt->parent;
        node* grandparent=parent->parent;
        parent->left=pt->right;
        node* q=pt;
        if(pt->right)
            pt->right->parent=parent;
        pt->right=parent;
        parent->parent=pt;
        pt->parent=grandparent;
        if(grandparent){
    
    
            if(grandparent->right==parent)
                grandparent->right=pt;
            else grandparent->left=pt;
        }else{
    
    //回去之后splay会帮你更新root
            root=pt;        
        }
        return pt;
    }
    void LL(node* p){
    
    
        sll++;
        L(p->parent);
        L(p);//回去之后splay会帮你更新root
    }
    void RR(node* p){
    
    
        srr++;
        R(p->parent);
        R(p);
    }
    void LR(node* p){
    
    
        slr++;
        L(p);//??????????
        R(p);
    }
    void RL(node* p){
    
    
        srl++;
        R(p);
        L(p);
    }
};

int main()
{
    
    
    tree bts;
    int t;
    cin >> t;
    while(t--){
    
    
        int temp1;
        cin >> temp1;
        bts.insert(temp1,bts.root);
    }
    cin >> t;
    while(t--){
    
    
        int temp2;
        string crush;
        cin >> crush >> temp2;
        bts.insert(temp2,bts.root);
    }
    //bts.print(bts.root);
    cin >> t;
    while(t--){
    
    
        string str;
        int temp3;
        cin >> str >> temp3;
        if(str.compare("QUERY")==0){
    
    
            if(!bts.find_return_splay(temp3,bts.root))cout << "the number is bad"<<endl;
            else cout << "the number is good" << endl;
        }else if(str.compare("DELETE")==0){
    
    
            bts.del(temp3);
        }
    }
    cout << "sr: " << bts.sr << endl;
    cout << "sl: " << bts.sl << endl;
    cout << "srr: " << bts.srr << endl;
    cout << "sll: " << bts.sll << endl;
    cout << "srl: " << bts.srl << endl;
    cout << "slr: " << bts.slr << endl;
    return 0;
}

问题 B: 宠物收养所(Splay —— 前驱后继操作)

题目描述

最近,贝贝开了一间宠物收养所。收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物。每个领养者都希望领养到自己满意的宠物,贝贝根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领养的宠物的特点值a(a是一个正整数,a<2^31),而他也给每个处在收养所的宠物一个特点值。

这样他就能够很方便的处理整个领养宠物的过程了,宠物收养所总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少。

1. 被遗弃的宠物过多时,假若到来一个领养者,这个领养者希望领养的宠物的特点值为a,那么它将会领养一只目前未被领养的宠物中特点值最接近a的一只宠物。(任何两只宠物的特点值都不可能是相同的,任何两个领养者的希望领养宠物的特点值也不可能是一样的)如果有两只满足要求的宠物,即存在两只宠物他们的特点值分别为a-b和a+b,那么领养者将会领养特点值为a-b的那只宠物。

扫描二维码关注公众号,回复: 13112461 查看本文章

2. 收养宠物的人过多,假若到来一只被收养的宠物,那么哪个领养者能够领养它呢?能够领养它的领养者,是那个希望被领养宠物的特点值最接近该宠物特点值的领养者,如果该宠物的特点值为a,存在两个领养者他们希望领养宠物的特点值分别为a-b和a+b,那么特点值为a-b的那个领养者将成功领养该宠物。 一个领养者领养了一个特点值为a的宠物,而它本身希望领养的宠物的特点值为b,那么这个领养者的不满意程度为abs(a-b)。

【任务描述】你得到了一年当中,领养者和被收养宠物到来收养所的情况,希望你计算所有收养了宠物的领养者的不满意程度的总和。这一年初始时,收养所里面既没有宠物,也没有领养者。

输入

第一行为一个正整数n,n<=80000,表示一年当中来到收养所的宠物和领养者的总数。接下来的n行,按到来时间的先后顺序描述了一年当中来到收养所的宠物和领养者的情况。每行有两个正整数a, b,其中a=0表示宠物,a=1表示领养者,b表示宠物的特点值或是领养者希望领养宠物的特点值。(同一时间呆在收养所中的,要么全是宠物,要么全是领养者,这些宠物和领养者的个数不会超过10000个)

输出

仅有一个正整数,表示一年当中所有收养了宠物的领养者的不满意程度的总和mod 1000000以后的结果。

样例输入

5
0 2
0 4
1 3
1 2
1 5

样例输出

3

提示

(abs(3-2) + abs(2-4)=3,最后一个领养者没有宠物可以领养)

代码

#include<iostream>
using namespace std;  
#define maxn 100005  
#define INF 1 << 31
int pre[maxn], node[maxn][2], value[maxn], rt, total;  
void newNode(int& r, int fa, int val){
    
     //初始化一个节点
    r = ++total;  
    pre[r] = fa;  
    value[r] = val;  
    node[r][0] = node[r][1] = 0;  
}  
void rotate(int r, int kind){
    
      
    int y = pre[r];  
    node[y][!kind] = node[r][kind];  
    pre[node[r][kind]] = y;  
    if(pre[y]){
    
      
        node[pre[y]][node[pre[y]][1] == y] = r;  
    }  
    node[r][kind] = y;  
    pre[r] = pre[y];  
    pre[y] = r;  
}  
void splay(int r, int goal){
    
      
    while(pre[r] != goal){
    
      //当r的父节点不为root
        if(pre[pre[r]] == goal){
    
    //如果r的祖父节点为root  
            rotate(r, node[pre[r]][0] == r);  
        }  
        else{
    
      //当r的父节点为root
            int y = pre[r];  //y为r的父节点
            int kind = node[pre[y]][0] == y;  
            if(node[pre[r]][!kind] == r){
    
      
                rotate(y, kind);  
                rotate(r, kind);  
            }  
            else{
    
      
                rotate(r, !kind);  
                rotate(r, kind);  
            }  
        }  
    }  
    if(goal == 0) rt = r;  
}  
int insert(int val){
    
      
    int r = rt;  
    while(1){
    
      
        if(val < value[r]){
    
      
            if(node[r][0]) r = node[r][0];  
            else break;  
        }  
        else if(val > value[r]){
    
      
            if(node[r][1]) r = node[r][1];  
            else break;  
        }  
        else{
    
    
        	splay(r, 0);
        	return 0;
        }  
    }  
    newNode(node[r][val > value[r]], r, val);  
    splay(node[r][val > value[r]], 0);  
    return 1;  
}  
int getmin(int val){
    
      
    int r = rt;  
    if(node[r][0] == 0) return 0;  
    r = node[r][0];  
    while(node[r][1]) r = node[r][1];  
    return value[r];  
}  
int getmax(int val){
    
      
    int r = rt;  
    r = node[r][1];  
    if(r == 0) return INF;  
    while(node[r][0]) r = node[r][0];  
    return value[r];  
} 
void findnode(int x){
    
    
	int r = rt;
	while(value[r] != x){
    
    
		if(x < value[r]) r = node[r][0];
		else r = node[r][1];
	}
	splay(r, 0);
}
void remove(){
    
    
	if(!rt) return;
	int y;
	if(node[rt][1] == 0){
    
    
		rt = node[rt][0];
	}
	else{
    
    
		y = node[rt][1];
		while(node[y][0]){
    
    
			y = node[y][0];
		}
		splay(y, rt);
		node[y][0] = node[rt][0];
		pre[node[rt][0]] = y;
		rt = y;
	}
	pre[rt] = 0;
} 
int main(){
    
      
    int n, x, op, cur, cnt;  
    scanf("%d", &n);  
    long long ans = 0;  //总和
    rt = total = 0;  
    for(int i = 1; i <= n; ++i){
    
      
    	ans %= 1000000;
        scanf("%d %d", &op, &x);  
        if(rt == 0){
    
      
            newNode(rt, 0, x);  
            cur = op;
            cnt = 1;
        }  
        else{
    
      
        	if(cnt == 0){
    
    
        		cnt += insert(x);
        		cur = op;
        	}
        	else if(op == cur){
    
    
        		cnt += insert(x);
        	}
            else if(insert(x) == 0){
    
      
            	cnt--;
            	remove();
                continue;  
            }  
            else{
    
      
                int l = getmin(x);  
                int r = getmax(x); 
                remove();
                if(l == 0){
    
    
                	ans += r - x;
                	remove();
                }
                else if(r == INF){
    
    
                	ans += x - l;
                	findnode(l);
                	remove();
                }
                else{
    
    
                	if(x - l > r - x){
    
    
                		ans += r - x;
                		findnode(r);
	                	remove();
                	}
                	else{
    
    
                		ans += x - l;
                		findnode(l);
	                	remove();
                	}
                }
                cnt--;
            }  
        }  
    }  
    ans %= 1000000;
    cout << ans << endl;
} 
 

猜你喜欢

转载自blog.csdn.net/NP_hard/article/details/111084593