关于替罪羊树找不到前驱这件事
  • 板块灌水区
  • 楼主Rioat
  • 当前回复10
  • 已保存回复10
  • 发布时间2022/7/9 10:28
  • 上次更新2023/10/27 21:23:52
查看原帖
关于替罪羊树找不到前驱这件事
739356
Rioat楼主2022/7/9 10:28

RT

https://www.luogu.com.cn/problem/P3369

救命,只有第11个点第2问(问前驱),没找到了,救救孩子。

会其他的平衡树,突发奇想写写替罪羊练练手,然后就坐牢了。

没有写合并相同节点,选择手写动态回收内存。

问题在第11个数据点,第2问找前驱时输出了0(完全没找到),答案输出了负值。

下不了数据非常的折磨。

#include <bits/stdc++.h>
using namespace std;
struct Node
{
    int le,ri;//左,右儿子
    int key;//关键值
    int cNt;//记录子树大小
}node[100100];//alpha现场计算
//如果你想写封装,那就写,主要是如果封装你要把一个树看作一个整体,不然写了根没写一样,可以考虑封装Splay或者FHQ,但是替罪羊真没必要
const double liMiT=0.75;
int root;//0就是目标点辣!
int head;//栈头,实现动态分配空间
int mAllcer[100100];//栈
int rEc;//记录最大重构树
int keyPark[100100];//reBuild的暂时停车场
int sTack_out()
{
    node[mAllcer[head]].le=0;
    node[mAllcer[head]].ri=0;
    node[mAllcer[head]].cNt=0;
    return mAllcer[head--];
}
void sTack_in(int poi)
{
    mAllcer[++head]=poi;
    return;
}
void pushup(int poi)
{
    node[poi].cNt=node[node[poi].le].cNt+node[node[poi].ri].cNt+1;
    return;
}
bool pan(int poi)
{
    double aLpha=double(max(node[node[poi].le].cNt,node[node[poi].ri].cNt))/double(node[poi].cNt);
    return aLpha>liMiT;
}
void Insert(int kEy,int poi)//poi for position
{
    if(kEy<node[poi].key)
    {
        if(node[poi].le==0)
        {
            node[poi].le=sTack_out();
            node[node[poi].le].key=kEy;
            node[node[poi].le].cNt=1;
        }
        else
        {
            Insert(kEy,node[poi].le);
        }
    }
    else
    {
        if(node[poi].ri==0)
        {
            node[poi].ri=sTack_out();
            node[node[poi].ri].key=kEy;
            node[node[poi].ri].cNt=1;
        }
        else
        {
            Insert(kEy,node[poi].ri);
        }
    }
    pushup(poi);
    if(pan(poi))
    {
        rEc=poi;
    }
    return;
}
int pArk_cnt;//停车场数组的计数器
void dfs_pArk(int poi)
{
    if(node[poi].le!=0)
    {
        dfs_pArk(node[poi].le);
        sTack_in(node[poi].le);
    }
    pArk_cnt++;
    keyPark[pArk_cnt]=node[poi].key;
    if(node[poi].ri!=0)
    {
        dfs_pArk(node[poi].ri);
        sTack_in(node[poi].ri);
    }
    return;
}
void build(int l,int r,int poi)//注意我们的rebuild方式无法保证相同的元素大小顺序关系
{
    int mid=(l+r)/2;
    node[poi].key=keyPark[mid];
    node[poi].cNt=1;
    if(l<=mid-1)
    {
        node[poi].le=sTack_out();
        build(l,mid-1,node[poi].le);
    }
    if(mid+1<=r)
    {
        node[poi].ri=sTack_out();
        build(mid+1,r,node[poi].ri);
    }
    pushup(poi);
    return;
}
//左子树:相同/比父节点小的
//右子树:相同/比父节点大的
void reBuild(int poi)
{
    if(poi==0)return;
    pArk_cnt=0;
    dfs_pArk(poi);
    //接树的时候注意这个函数的poi不会被回收掉,poi就是新树的根!
    //按照这个写法只能这样,因为上面的树还连接着poi;
    node[poi].le=0;
    node[poi].ri=0;
    //切断连接
    build(1,pArk_cnt,poi);
    // pushup(poi);
    return;
}
void sTack_init(int num)
{
    for(int i=1;i<=num;i++)
    {
        sTack_in(i);
    }
    return;
}
// int Merge(int l,int r)
// {
//     if(!l||!r)
//     {
//         return l+r;
//     }
//     int a=rand();
//     int b=rand();
//     int poi;
//     if(a>b)
//     {
//         poi=Merge(node[l].ri,r);
//         node[l].ri=poi;
//     }
//     else
//     {
//         poi=Merge(node[r].le,l);
//         node[r].le=poi;
//     }
//     pushup(poi);
//     if(pan(poi))rEc=poi;
//     return poi;
// }
int Merge(int l,int r)
{
    if(!l||!r)
    {
        return l+r;
    }
    int a=rand();
    int b=rand();
    if(a<b)
    {
        node[l].ri=Merge(node[l].ri,r);
        pushup(l);
        if(pan(l))rEc=l;
        return l;
    }
    else
    {
        node[r].le=Merge(l,node[r].le);
        pushup(r);
        if(pan(r))rEc=r;
        return r;
    }
}
void Dlete(int kEy,int poi,int fat,bool pan)//可以写懒惰删除,但是感觉懒惰删除好low
{
    if(poi==0)return;//题设肯定存在,只是万一错误操作。。。我写一个在这里
    if(node[poi].key==kEy)
    {
        //1.在poi处合并两颗子树,fhq_treap的merge()操作
        //2.把左树直接放在右树的叶节点并且重新统计并重构
        //根节点被删掉就完力!
        if(fat==0)
        {
            root=Merge(node[poi].le,node[poi].ri);
            // pushup(root);
            sTack_in(poi);
            return;
        }
        if(pan==0)
        {
            node[fat].le=Merge(node[poi].le,node[poi].ri);
        }
        else
        {
            node[fat].ri=Merge(node[poi].le,node[poi].ri);
        }
        sTack_in(poi);
        return;
    }
    if(kEy<node[poi].key)
    {
        Dlete(kEy,node[poi].le,poi,0);
        pushup(poi);
    }
    else
    {
        Dlete(kEy,node[poi].ri,poi,1);
        pushup(poi);
    }
    return;
}
void rAnk(int kEy,int poi)
{
    if(kEy==node[node[poi].le].cNt+1)
    {
        printf("%d\n",node[poi].key);
        // printf("f\n");
        return;
    }
    if(kEy<node[node[poi].le].cNt+1)
    {
        rAnk(kEy,node[poi].le);
    }
    else
    {
        rAnk(kEy-node[node[poi].le].cNt-1,node[poi].ri);
    }
    return;
}
void FindRank(int kEy,int poi,int ans)//因为reBuild方式,所以不得不这样
{
    if(poi==0)
    {
        printf("%d\n",ans+1);
        return;
    }
    if(node[poi].key<kEy)
    {
        ans+=node[node[poi].le].cNt+1;
        FindRank(kEy,node[poi].ri,ans);
    }
    else
    {
        FindRank(kEy,node[poi].le,ans);
    }
    return;
}
void fro_Num(int kEy,int poi,int ans)//数据正常,有前驱的情况下
{
    if(poi==0)
    {
        printf("%d\n",node[ans].key);
        // printf("f\n");
        return;
    }
    if(node[poi].key<kEy)
    {
        fro_Num(kEy,node[poi].ri,poi);
    }
    else
    {
        fro_Num(kEy,node[poi].le,ans);
    }
    return;
}
//fro_Num
void bac_Num(int kEy,int poi,int ans)//数据正常,有前驱的情况下
{
    if(poi==0)
    {
        printf("%d\n",node[ans].key);
        return;
    }
    if(node[poi].key<=kEy)
    {
        bac_Num(kEy,node[poi].ri,ans);
    }
    else
    {
        bac_Num(kEy,node[poi].le,poi);
    }
    return;
}
// int cont;
// void dfs_out(int poi)
// {
//     if(poi==0)
//     {
//         return;
//     }
//     dfs_out(node[poi].le);
//     printf("%d ",node[poi].key);
//     cont++;
//     dfs_out(node[poi].ri);
//     return;
// }
int main()
{
    // freopen("input","r",stdin);
    // freopen("ans","w",stdout);
    srand(time(0));
    int num,opt,kEy;
    scanf("%d",&num);
    sTack_init(num);
    scanf("%d %d",&opt,&kEy);
    if(opt==1)
    {
        root=sTack_out();
        node[root].key=kEy;
        node[root].cNt=1;
    }
    for(int i=1;i<num;i++)
    {
        scanf("%d %d",&opt,&kEy);
        switch (opt)
        {
        case 1:
            rEc=0;
            Insert(kEy,root);
            reBuild(rEc);
            break;
        case 2:
            rEc=0;
            Dlete(kEy,root,0,0);
            reBuild(rEc);
            break;
        case 3:
            FindRank(kEy,root,0);//
            break;
        case 4:
            rAnk(kEy,root);
            break;
        case 5:
            fro_Num(kEy,root,0);
            break;
        case 6:
            bac_Num(kEy,root,0);
        default:
            break;
        }
    }
    // dfs_out(root);
    // printf("\n%d\n",cont);
    return 0;
}
//1,2,4操作无问题
2022/7/9 10:28
加载中...