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


 不得不說,做過最爽的樹套樹————

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

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

                 如果修改的話2*n+∑(i=1~log₂n-1)[17-∑(j=1~log₂n-j+2)[(2i-1)/2i]]*n*2,平均每個點280個

 這樣的話我們就需要回收空間了,不僅是在重建的時候,也必須得是在修改的時候(別問我為什么這么說QAQ),把他維持到152個以內

時間復雜度:一開始的點用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     

             所以總時間復雜度:O(q*log₂3n)估大一點200000*173也就是109由於每個點10s也就行了

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

#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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM