洛谷P3835 【模板】可持久化平衡樹

自為風月馬前卒發表於2017-12-09

題目背景

本題為題目 普通平衡樹 的可持久化加強版。

資料已經經過強化

題目描述

您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作(對於各個以往的歷史版本):

  1. 插入x數

  2. 刪除x數(若有多個相同的數,因只刪除一個,如果沒有請忽略該操作)

  3. 查詢x數的排名(排名定義為比當前數小的數的個數+1。若有多個相同的數,因輸出最小的排名)

  4. 查詢排名為x的數

  5. 求x的前驅(前驅定義為小於x,且最大的數,如不存在輸出-2147483647)

  6. 求x的後繼(後繼定義為大於x,且最小的數,如不存在輸出2147483647)

和原本平衡樹不同的一點是,每一次的任何操作都是基於某一個歷史版本,同時生成一個新的版本。(操作3, 4, 5, 6即保持原版本無變化)

每個版本的編號即為操作的序號(版本0即為初始狀態,空樹)

輸入輸出格式

輸入格式:

 

第一行包含一個正整數N,表示操作的總數。

接下來每行包含三個正整數,第 ii 行記為 v_i, opt_i, x_ivi,opti,xi

v_ivi表示基於的過去版本號( 0 \leq v_i < i0vi<i ),opt_iopti 表示操作的序號( 1 \leq opt \leq 61opt6 ), x_ixi 表示參與操作的數值

 

輸出格式:

 

每行包含一個正整數,依次為各個3,4,5,6操作所對應的答案

 

輸入輸出樣例

輸入樣例#1: 複製
10
0 1 9
1 1 3
1 1 10
2 4 2
3 3 9
3 1 2
6 4 1
6 2 9
8 6 3
4 5 8
輸出樣例#1: 複製
9
1
2
10
3

說明

資料範圍:

對於10%的資料滿足: 1 \leq n \leq 101n10

對於30%的資料滿足: 1 \leq n \leq 2\cdot {10}^21n2102

對於50%的資料滿足: 1 \leq n \leq 3\cdot {10}^31n3103

對於80%的資料滿足: 1 \leq n \leq {10}^51n105

對於90%的資料滿足: 1 \leq n \leq 2\cdot {10}^51n2105

對於100%的資料滿足: 1 \leq n \leq 5\cdot {10}^51n5105 , -{10}^9 \leq x_i \leq {10}^9109xi109

經實測,正常常數的可持久化平衡樹均可通過,請各位放心

樣例說明:

共10次操作,11個版本,各版本的狀況依次是:

  1. [][]

  2. [9][9]

  3. [3, 9][3,9]

  4. [9, 10][9,10]

  5. [3, 9][3,9]

  6. [9, 10][9,10]

  7. [2, 9, 10][2,9,10]

  8. [2, 9, 10][2,9,10]

  9. [2, 10][2,10]

  10. [2, 10][2,10]

  11. [3, 9][3,9]

 

也是沒誰了

資料壓根就沒有5.6的21***的情況

而且不知道為啥我的樣例沒過就A了。。

 

#include<bits/stdc++.h>
using namespace std;
#define ls tree[k].ch[0]
#define rs tree[k].ch[1]
const int MAXN=1e6+10,INF=1e7;
inline char nc()
{
    static char buf[MAXN],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    char c=nc();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=nc();}
    return x*f;
}
struct node
{
    int pri,v,ch[2],siz;
}tree[MAXN];
int x,y,z,tot=0,root[MAXN];
int new_node(int val)
{
    tree[++tot].pri=rand()*rand(),tree[tot].v=val,tree[tot].siz=1;
    return tot;
}
void update(int k){   tree[k].siz=tree[ls].siz+tree[rs].siz+1; }
void split(int now,int k,int &x,int &y)
{
    if(!now)  {x=y=0;return ;}
    if(tree[now].v<=k)  x=now,split(tree[now].ch[1],k,tree[now].ch[1],y);
    else y=now,split(tree[now].ch[0],k,x,tree[now].ch[0]);
    update(now);
}
int merge(int x,int y)
{
    if(!x||!y)  return x+y;
    if(tree[x].pri<tree[y].pri) {tree[x].ch[1]=merge(tree[x].ch[1],y),update(x);return x;}
    else {tree[y].ch[0]=merge(x,tree[y].ch[0]),update(y);return y;}
}
int kth(int k,int x)// 查詢排名 
{
    if(x<=tree[ls].siz)           return kth(ls,x);
    else if(x==tree[ls].siz+1)    return k;
    else return kth(rs,x-tree[ls].siz-1);
}
int main()
{ 
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #else 
    #endif
    srand((unsigned)time(NULL));
    int n=read();
    for(int i=1;i<=n;i++)
    {
        int pre=read(),how=read(),a=read();
        root[i]=root[pre];     
        if(how==1)      split(root[i],a,x,y),root[i]=merge(merge(x,new_node(a)),y);
        else if(how==2) split(root[i],a,x,z),split(x,a-1,x,y),y=merge(tree[y].ch[0],tree[y].ch[1]),root[i]=merge(merge(x,y),z);
        else if(how==3) split(root[i],a-1,x,y),printf("%d\n",tree[x].siz+1),root[i]=merge(x,y);
        else if(how==4) printf("%d\n",tree[kth(root[i],a)].v);
        else if(how==5)    split(root[i],a-1,x,y),printf("%d\n",tree[kth(x,tree[x].siz)].v),root[i]=merge(x,y);
        else if(how==6) split(root[i],a,x,y),printf("%d\n",tree[kth(y,1)].v),root[i]=merge(x,y);
    }
    return 0;
}

 

相關文章