【bzoj3065】: 帶插入區間K小值 詳解——替罪羊套函數式線段樹

 不得不說,作過最爽的樹套樹————html

因爲有了區間操做,咱們很容易把區間當作一棵平衡樹,對他進行插入,那麼外面一層就是平衡樹了,這就與咱們以前所見到的不一樣了。咱們以前所見到的大多數是線段樹套平衡樹而此題中插入時座標會改變即必須對其找到合適的順序,而線段樹無疑是不支持動態插入的,他維護的是一個靜態區間(由於插入一個點整個區間的二分結構可能所有改變,這用他就沒法經過區間二分來維護信息了)。因此說咱們必須來進行平衡樹套線段樹,那麼平衡樹就須要維護區間,而線段樹就須要維護權值,以前咱們的樹套樹,在外邊一個靜態區間線段樹裏面每一個節點都有這個點dfs序所對應區間裏的數的有序排列,在這裏咱們用平衡樹來維護區間,那麼對於裏面的點,YY一下,也是對應於父子關係的一段區間,但咱們沒法將裏面的點有序化,可是咱們獲得了一個可視且可用的一段取值區間這樣咱們就能夠用動態開點來維護權值信息,通常的平衡樹像Splay Treap都須要旋轉操做而每次旋轉裏面的線段樹維護的權值信息都會隨着父子關係的改變而改變,每次都須要新的線段樹(合併也行),常數大到飛起(Treap插入乘個log,Spaly插入乘個log查詢log2,雖然看起來沒那麼差甚至根由更優,可是想想常數),那麼替罪羊就要來當大佬了(表示不會無旋Treap),這樣只有每次重構纔會將重建(合併)線段樹,大約有㏒₂n次重建。node

 空間複雜度:替罪羊n;線段樹若是不修改  ∑(i=1 ~log2n)n*[log2n-∑(j=1~log2n-i+1)[(2i-1)/2i]],平均每一個點152個,ios

                 若是修改的話2*n+∑(i=1~log₂n-1)[17-∑(j=1~log₂n-j+2)[(2i-1)/2i]]*n*2,平均每一個點280個數據結構

 這樣的話咱們就須要回收空間了,不只是在重建的時候,也必須得是在修改的時候(別問我爲何這麼說QAQ),把他維持到152個之內ide

時間複雜度:一開始的點用O(n+nlog₂²n),每次插入O(log₂²n),修改O(log₂²n),查詢:每一層被選中的點和根(不要忘了咱們是在分平衡樹千萬不要忘了中間那個點)的個數不超過四個(這個我不會理性的證,我先感性的證一下:1.你把這棵樹建出來,開始在同一深度找,找到五個的時候怎麼也找不到2.這麼吊的數據結構查詢怎麼也得是log級別的啊),因此就是O(log₂n+log₂3n),總重建O(log₂n*(n+∑(i=1 ~log2n)n*[log2n-∑(j=1~log2n-i+1)[(2i-1)/2i]]+n*log²n))大約10*log²n*n     ui

             因此總時間複雜度:O(q*log₂3n)估大一點200000*173也就是109因爲每一個點10s也就好了spa

然而人傻自帶大常數........code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define MAXN 140100
#define inf 70000
using namespace std;
inline int read()
{
   int s=0;
   char ch=getchar();
   while(ch<'0'||ch>'9')ch=getchar();
   while(ch>='0'&&ch<='9')
   {
      s=(s<<3)+(s<<1)+ch-48;
      ch=getchar();
   }
   return s;
}
const double alpha=0.75;
struct Tree
{
   Tree *ch[2];
   int size,l,r,mid;
}*null,*stack[120*MAXN],pool[120*MAXN],*now[MAXN];
int Now[MAXN],num,Num;
int list[MAXN],len;
int top;
struct ScapeGoat_Tree
{
   ScapeGoat_Tree *ch[2];
   int size,key;
   Tree *root;
   bool bad()
   {
     return size*alpha+5<ch[0]->size||size*alpha+5<ch[1]->size;
   }
   void pushup()
   {
     size=ch[0]->size+ch[1]->size+1;
   }
}*Null,*root,*lst[MAXN],node[MAXN];
int sz;
inline void Init()
{
   null=pool;
   null->size=null->l=null->r=null->mid=0;
   null->ch[1]=null->ch[0]=null;
   for(int i=1;i<(100*MAXN);i++)stack[++top]=pool+i;
   Null=node;
   Null->size=Null->key=0;
   Null->ch[1]=Null->ch[0]=Null;
   Null->root=null;
   root=Null;
}
inline Tree *New(int l,int r)
{
   Tree *p=stack[top--];
   p->l=l;
   p->r=r;
   p->mid=(l+r)>>1;
   p->size=0;
   p->ch[0]=p->ch[1]=null;
   return p;
}
inline ScapeGoat_Tree *New(int key)
{
   ScapeGoat_Tree *p=&node[++sz];
   p->ch[0]=p->ch[1]=Null;
   p->size=1;
   p->key=key;
   p->root=null;
   return p;
}
void recovery(Tree *p)
{
   if(p==null)return;
   recovery(p->ch[0]);
   stack[++top]=p;
   recovery(p->ch[1]);
}
void travel(ScapeGoat_Tree *p)
{
   if(p==Null)return;
   travel(p->ch[0]);
   lst[++len]=p;
   list[len]=p->key;
   recovery(p->root);
   p->root=null;
   travel(p->ch[1]);
}
void ins(Tree *&p,int key,int l,int r)
{
   if(p==null)p=New(l,r);
   p->size++;
   if(p->l==p->r)return;
   if(p->mid<key) ins(p->ch[1],key,p->mid+1,r);
   else ins(p->ch[0],key,l,p->mid);
}
ScapeGoat_Tree *divide(int l,int r)
{
   if(l>r)return Null;
   int mid=(l+r)>>1;
   for(int i=l;i<=r;i++)ins(lst[mid]->root,list[i],0,inf);
   lst[mid]->ch[0]=divide(l,mid-1);
   lst[mid]->ch[1]=divide(mid+1,r);
   lst[mid]->pushup();
   return lst[mid];
}
void Ins(ScapeGoat_Tree *p,int key,int pos)
{
   ins(p->root,key,0,inf);
   if(p->ch[0]->size+1==pos)
   {
      p->key=key;
      return;
   }
   if(p->ch[0]->size>=pos)Ins(p->ch[0],key,pos);
   else Ins(p->ch[1],key,pos-p->ch[0]->size-1);
}
inline void rebuild(ScapeGoat_Tree *&p)
{
   len=0;
   travel(p);
   p=divide(1,len);
}
ScapeGoat_Tree **insert(ScapeGoat_Tree *&p,int key,int pos)
{
   if(p==Null)
   {
     p=New(key);
     ins(p->root,key,0,inf);
     return &Null;
   }
   p->size++;
   ins(p->root,key,0,inf);
   ScapeGoat_Tree **ret;
   if(p->ch[0]->size+1>=pos)ret=insert(p->ch[0],key,pos);
   else ret=insert(p->ch[1],key,pos-p->ch[0]->size-1);
   if(p->bad())ret=&p;
   return ret;
}
inline void Insert(int key,int pos)
{
   ScapeGoat_Tree **p=insert(root,key,pos);
   if(*p!=Null)rebuild(*p);
}
inline int find(int pos)
{
   ScapeGoat_Tree *p=root;
   while(1)
    if(p->ch[0]->size+1==pos)return p->key;
    else if(p->ch[0]->size>=pos)p=p->ch[0];
    else pos-=p->ch[0]->size+1,p=p->ch[1];
}
void del(Tree *&p,int key)
{
   p->size--;
   if(p->l==p->r)
   {
      if(p->size==0)
      {
         stack[++top]=p;
         p=null;
      }
      return;
   }
   del(p->ch[p->mid<key],key);
   if(p->size==0)
   {
     stack[++top]=p;
     p=null;
   }
}
void Del(ScapeGoat_Tree *p,int pos,int key)
{
   del(p->root,key);
   if(p->ch[0]->size+1==pos)return;
   if(p->ch[0]->size>=pos)Del(p->ch[0],pos,key);
   else Del(p->ch[1],pos-p->ch[0]->size-1,key);
}
int rank(Tree *p,int key)
{
   if(p==null)return 0;
   if(p->l==p->r)return 0;
   if(key<=p->mid)return rank(p->ch[0],key);
   else return p->ch[0]->size+rank(p->ch[1],key);
}
void pre(ScapeGoat_Tree *p,int l,int r)
{
   if(p==Null)return;
   if(l<=1&&p->size<=r)
   {
      now[++num]=p->root; 
      return;
   }
   if(l<=p->ch[0]->size)pre(p->ch[0],l,r);
   if(l<=p->ch[0]->size+1&&r>=p->ch[0]->size+1)Now[++Num]=p->key;
   if(p->ch[0]->size+1<r)pre(p->ch[1],l-p->ch[0]->size-1,r-p->ch[0]->size-1);
}
inline int Rank(int x)
{
   int ans=0;
   for(int i=1;i<=num;i++)
    ans+=rank(now[i],x);
   for(int i=1;i<=Num;i++)
    if(x>Now[i])ans++;
    else break;
   return ans;
}
int lastans=0;
inline void work1()
{
   int x=read()^lastans,y=read()^lastans,k=read()^lastans;
   if(x>y)x^=y^=x^=y;
   num=Num=0;
   pre(root,x,y);
   sort(Now+1,Now+Num+1);
   int l=0,r=inf,ans=0;
   while(l<=r)
   {
     int mid=(l+r)>>1;
     int tmp=Rank(mid)+1;
     if(tmp<=k)
      ans=mid,l=mid+1;
     else
      r=mid-1;
   }
   lastans=ans;
   printf("%d\n",ans);
}
inline void work2()
{
   int x=read()^lastans,val=read()^lastans;
   Del(root,x,find(x));
   Ins(root,val,x);
}
inline void work3()
{
   int x=read()^lastans,val=read()^lastans;
   Insert(val,x);
}
int main()
{
    Init();
    int n=read();
    for(int i=1;i<=n;i++)
    {
      list[++len]=read();
      lst[len]=New(list[len]);
    }
    root=divide(1,len);
    int Q=read();
    while(Q--)
    {
       char s[2];
       scanf("%s",s);
       if(s[0]=='Q')work1();
       if(s[0]=='M')work2();
       if(s[0]=='I')work3();
    }
    return 0;
}
相關文章
相關標籤/搜索