【非旋treap】 fhq-treap總結及模板

各位大佬講得真好   我既然講不好就不講了

http://www.cnblogs.com/mjtcn/p/8028926.html

https://blog.csdn.net/cabi_zgx/article/details/79963427

https://www.luogu.org/blog/Chanis/fhq-treap

https://www.cnblogs.com/BCOI/p/9072444.html

非旋treap常數大 

【模板】普通平衡樹

題目描述

您需要寫一種數據結構(可參考題目標題),來維護一些數,其中需要提供以下操作:

  1. 插入x數
  2. 刪除x數(若有多個相同的數,因只刪除一個)
  3. 查詢x數的排名(排名定義爲比當前數小的數的個數+1。若有多個相同的數,因輸出最小的排名)
  4. 查詢排名爲x的數
  5. 求x的前驅(前驅定義爲小於x,且最大的數)
  6. 求x的後繼(後繼定義爲大於x,且最小的數)

輸入輸出格式

輸入格式:

第一行爲n,表示操作的個數,下面nn行每行有兩個數opt和x,opt表示操作的序號(1≤opt≤6 )

輸出格式:

對於操作3,4,5,6每行輸出一個數,表示對應答案

輸入輸出樣例

輸入樣例#1: 

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

輸出樣例#1:

106465
84185
492737

說明

時空限制:1000ms,128M

1.n的數據範圍: n≤100000

2.每個數的數據範圍: [-10^7, 10^7]

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5*100000+5;
int num,root,ch[N][2],val[N],rnd[N],siz[N];

inline void pushup(int x) 
  {siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;}
  
inline int  make(int x) 
 {val[++num]=x; rnd[num]=rand(); siz[num]=1; 
  return num;
 }
 
void split(int now,int k,int &x,int &y)
 {if(!now) x=y=0;
  else 
     {if(val[now]<=k)
        {x=now; split(ch[now][1],k,ch[now][1],y);
        }
      else 
        {y=now; split(ch[now][0],k,x,ch[now][0]);
        }
      pushup(now);  
     }
 }
 
int merge(int x,int y) 
 {if(!x || !y) return x+y;
 
  if(rnd[x]<=rnd[y])
    {ch[x][1]=merge(ch[x][1],y);
     pushup(x); return x;
    }
  else 
    {ch[y][0]=merge(x,ch[y][0]);
     pushup(y); return y;
    }  
 }
 
inline int getkth(int p,int k)
 {while(1)
   {if(k==siz[ch[p][0]]+1) return p;
    if(ch[p][0] && k<=siz[ch[p][0]]) p=ch[p][0];
    else {k=k-siz[ch[p][0]]-1;
          p=ch[p][1];
         }
   }
 } 
int main()
{int m,op,k,x,y,z; scanf("%d",&m);	
    
 while(m--)	
  {scanf("%d%d",&op,&k);
    if(op==1)	
  	 {split(root,k,x,y);
  	  root=merge(merge(x,make(k)),y);
  	 }
   else	if(op==2)	
  	 {split(root,k,x,y);
  	  split(x,k-1,x,z);
  	  z=merge(ch[z][0],ch[z][1]);
  	  root=merge(merge(x,z),y);
  	 }
   else	if(op==3)	
  	 {split(root,k-1,x,y);
  	  printf("%d\n",siz[x]+1);
  	  root=merge(x,y);
  	 }
   else	if(op==4)	
  	 {printf("%d\n",val[getkth(root,k)]);
  	 }
   else	if(op==5)	
  	 {split(root,k-1,x,y);
  	  printf("%d\n",val[getkth(x,siz[x])]);
  	  root=merge(x,y);
  	 }
   else	if(op==6)	
  	 {split(root,k,x,y);
  	  printf("%d\n",val[getkth(y,1)]);
  	  root=merge(x,y);
  	 }  
  }	
return 0;
}

BZOJ1251: 序列終結者

Description

網上有許多題,就是給定一個序列,要你支持幾種操作:A、B、C、D。一看另一道題,又是一個序列 要支持幾種操作:D、C、B、A。尤其是我們這裏的某人,出模擬試題,居然還出了一道這樣的,真是沒技術含量……這樣 我也出一道題,我出這一道的目的是爲了讓大家以後做這種題目有一個“庫”可以依靠,沒有什麼其他的意思。這道題目 就叫序列終結者吧。 【問題描述】 給定一個長度爲N的序列,每個序列的元素是一個整數(廢話)。要支持以下三種操作: 1. 將[L,R]這個區間內的所有數加上V。 2. 將[L,R]這個區間翻轉,比如1 2 3 4變成4 3 2 1。 3. 求[L,R]這個區間中的最大值。 最開始所有元素都是0。

Input

第一行兩個整數N,M。M爲操作個數。 以下M行,每行最多四個整數,依次爲K,L,R,V。K表示是第幾種操作,如果不是第1種操作則K後面只有兩個數。

Output

對於每個第3種操作,給出正確的回答。

Sample Input

4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4

Sample Output

2
【數據範圍】
N<=50000,M<=100000。

重點----0號節點的初始化 

否則有一個兒子爲空的時候pushup 負數時會導致max值爲不存在的0

 

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=50000+5; const int INF=0x3f3f3f;
int n,root,num,ls[N],rs[N],rnd[N],siz[N],val[N],add[N],maxx[N]; bool rev[N];
inline int make(int x)
 {rnd[++num]=rand(); val[num]=maxx[num]=x; siz[num]=1; return num;}
 
inline void pass(int i,long long v)
 {if(!i) return;
  add[i]+=v; maxx[i]+=v; val[i]+=v;
 } 
inline void pushup(int i)
 {siz[i]=siz[ls[i]]+siz[rs[i]]+1;
  maxx[i]=max(val[i],max(maxx[ls[i]],maxx[rs[i]]));
 } 
 
inline void pushdown(int i)
 {if(!i) return;
  if(rev[i])
   {rev[i]=0;
    swap(ls[i],rs[i]);
    if(ls[i]) rev[ls[i]]^=1;
    if(rs[i]) rev[rs[i]]^=1; 
   }
  
  if(add[i])
   {pass(ls[i],add[i]);  
    pass(rs[i],add[i]);
    
    add[i]=0;
   } 
 } 
 
void split(int now,int k,int &x,int &y)
 {if(!now) {x=y=0;return;}
  pushdown(now);
  if(k<=siz[ls[now]])
    {y=now; split(ls[now],k,x,ls[now]);
    }
  else 
    {x=now; split(rs[now],k-siz[ls[now]]-1,rs[now],y);
    }  
  pushup(now);  
 } 

int merge(int x,int y)
 {if(!x || !y) return x+y;
 
  pushdown(x); pushdown(y); 
  if(rnd[x]<=rnd[y])
    {rs[x]=merge(rs[x],y);
     pushup(x); return x;
    }
  else 
    {ls[y]=merge(x,ls[y]);
     pushup(y); return y;
    }  
 } /*
void print(int x)
 {if(!x) return;
  pushdown(x);
  print(ls[x]);
  printf("%d ",val[x]);
  print(rs[x]);
 }*/

int main()
{
 int m,l,r,op,x,y,z,v; scanf("%d%d",&n,&m);	
 
 maxx[0]=-INF;  //0號節點初始化
 
 while(n--) {root=merge(root,make(0));}	
	
 while(m--)	
  {scanf("%d%d%d",&op,&l,&r);
  
   split(root,r,x,y);
   split(x,l-1,x,z);
   
   if(op==1){scanf("%d",&v); pass(z,v); }
   else if(op==2) rev[z]^=1;
   else           printf("%d\n",maxx[z]);
     
   root=merge(merge(x,z),y);
  // print(root); printf("\n");
  }		
return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章