[Splay]扑克游戏

题目描述

有一棵无穷大的满二叉树,根为star,其余所有点的权值为点到根的距离,如图:
  这里写图片描述
  现在你有一些扑克牌,点数从1到13,你要把这些扑克牌全部放到这个树上:
  1. 当你把点数为i的扑克牌放在权值为j的点上,那么你会得到i*j的分数。
  2. 当你把一个扑克牌放在一个节点上,那么你就不能把别的扑克牌放在这个节点以及这个节点的子树上。
  你的目标是最小化你的得分。

Input
输入第一行为一个数字N,表示你有的扑克牌数;
接下来一行N个数字,数字在1到13之间。

Output
一个数字,最小得分。

Sample Input
3
5 10 13

Sample Output
43

【数据范围】
  30%数据 N<=100
  100%数据满足1<=N<=10000.

分析

这题非常像就是合并果子
以往合并果子都是直接用堆排快排的,蒟蒻这次比赛时绝望地码了Splay(才不是不会打小根堆呢)
然后就肥肠简单了

#include <iostream>
#include <cstdio>
#include <algorithm>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
int n,ans;
struct node {
    int c[2],f;
    int cnt,key;
}t[20001];
int rt,cnt;

void Clear(int x) {
    t[x].c[0]=t[x].c[1]=t[x].f=t[x].key=t[x].cnt=0;
}

int Get_f(int x) {
    return x==t[t[x].f].c[1];
}

void Rotate(int x)
{
    int f=t[x].f,gf=t[f].f,lr=Get_f(x);
    t[f].c[lr]=t[x].c[lr^1];t[t[f].c[lr]].f=f;
    t[x].c[lr^1]=f;t[f].f=x;
    t[x].f=gf;
    if (gf) t[gf].c[f==t[gf].c[1]]=x;
}


void Splay(int x,int goal) {
    for (int f;(f=t[x].f)!=goal;Rotate(x))
    if (t[f].f) Rotate((Get_f(x)==Get_f(f))?f:x);
    rt=x;
}

void Insert(int key) {
    if (!rt) {
        cnt++;rt=cnt;
        t[cnt].key=key;
        t[cnt].cnt++;
        t[cnt].c[0]=t[cnt].c[1]=0;
        return;
    }
    int x=rt,f=0;
    while (1) {
        if (t[x].key==key) {
            t[x].cnt++;
            Splay(x,0);
            return;
        }
        f=x;x=t[x].c[key>t[x].key];
        if (!x) {
            cnt++;
            t[cnt].key=key;
            t[cnt].cnt++;
            t[cnt].c[0]=t[cnt].c[1]=0;
            t[f].c[key>t[f].key]=cnt;t[cnt].f=f;
            Splay(cnt,0);
            return;
        }
    }
}

void Move(int key) {
    int x=rt;
    while (x) {
        if (key<t[x].key) 
        x=t[x].c[0];
        else {
            if (t[x].key==key) {
                Splay(x,0);
                return;
            }
            x=t[x].c[1];
        }
    }
}

int Get_small() {
    int x=rt;
    while (t[x].c[0]) x=t[x].c[0];
    return t[x].key;
}

int Get_pre() {
    int x=t[rt].c[0];
    while (t[x].c[1]) x=t[x].c[1];
    return x;
}

void Delete(int key) {
    Move(key);
    if (t[rt].cnt>1) {
        t[rt].cnt--;
        return;
    }
    if (!t[rt].c[1]&&!t[rt].c[0]) {
        Clear(rt);rt=0;
        return;
    }
    if (!t[rt].c[1]) {
        int oldrt=rt;
        rt=t[rt].c[0];
        t[rt].f=0;
        Clear(oldrt);
        return;
    }
    else 
    if (!t[rt].c[0]) {
        int oldrt=rt;
        rt=t[rt].c[1];
        t[rt].f=0;
        Clear(oldrt);
        return;
    }
    int oldrt=rt;
    Splay(Get_pre(),0);
    t[rt].c[1]=t[oldrt].c[1];
    t[t[rt].c[1]].f=rt;
    Clear(oldrt);
}

int main() {
    int i,a;
    scanf("%d",&n);
    rep(i,1,n)
    scanf("%d",&a),Insert(a);
    while (t[rt].c[0]||t[rt].c[1]) {
        int x1=Get_small();
        Delete(x1);
        int x2=Get_small();
        Delete(x2);
        ans+=x1+x2;
        Insert(x1+x2);
    }
    printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/ssl_qyh0ice/article/details/80942104