(写篇博客证明自己还活着)

在OI中,有些时候我们会遇到一些维护多维信息的题目,比如经典的三维偏序,或者带修改区间k小值

这个时候有的dalao就会跳出来大喊“整体二分!”“CDQ!”

然而这并不是我们今天讨论的重点……并且在强制在线的情况下,上面这两种算法就无能为力了。

那么我们就需要用数据结构乱堆树套树的方法来解决这类问题。这类树套树解法以码量大和难调试著称。

通过用一种(棵?)数据结构维护一维信息,我们可以实现在线地维护多维信息。

那么让我们开始总结一下树套树吧!


一.线段树/树状数组套平衡树

这大概是没接触过树套树的同学接触的第一种树套树类型吧。。。

这种套法一般是用外层的树维护区间信息,在外层树的每一个节点放一棵内层树,内层的树维护权值信息。

比如说查区间第k大,用套平衡树的做法就是二分权值val->到这个区间对应的log个线段树节点上查val的rank值,加起来与目标值进行比较

这种做法的空间需求是$O(nlogn)$的,由于每个元素都会在logn个外层树节点中插入自己

而时间复杂度上,除了查询区间第k大,每次操作是O(nlog2n)的,

由于在logn个外层树上都要用$O(logn)$的时间查询

查询第k大是$O(nlog3n)$的,由于在logn个外层树上都要用$O(logn)$的时间查询。

这种类型的树套树,经典的有:

bzoj3196 二逼平衡树

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<ctime>
  5 #include<cmath>
  6 using namespace std;
  7 const int N=50000+10;
  8 int val[N],n,m,a,b,c,o;
  9 struct node
 10 {
 11     node* ch[2];
 12     int rank,val,size,ge;
 13     node (int x){val=x;rank=rand();size=ge=1;ch[1]=ch[0]=NULL;}
 14     void tain()
 15     {
 16         size=1;
 17         if(ch[0])size+=ch[0]->size;
 18         if(ch[1])size+=ch[1]->size;
 19     }
 20 };
 21 inline int s(node* o){return o?o->size:0;}
 22 node* root[4*N];
 23 void rotate(node* &o,int d)
 24 {
 25     node* k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
 26     o->tain();k->tain();o=k;
 27 }
 28 void insert(node* &o,int val)
 29 {
 30     if(o==NULL){o=new node(val);return;}
 31     if(val<o->val)
 32     {
 33         insert(o->ch[0],val);
 34         if(o->ch[0]->rank > o->rank)
 35             rotate(o,1);
 36     }
 37     else
 38     {
 39         insert(o->ch[1],val);
 40         if(o->ch[1]->rank > o->rank)
 41             rotate(o,0);
 42     }
 43     o->tain();
 44 }
 45 inline void build(int le,int ri,int num)
 46 {
 47     for(int i=le;i<=ri;i++)insert(root[num],val[i]);
 48 }
 49 void treeins(int le,int ri,int num)
 50 {
 51     build(le,ri,num);
 52     if(le==ri)return;
 53     int mi=(le+ri)>>1;
 54     treeins(le,mi,num<<1);
 55     treeins(mi+1,ri,(num<<1)|1);
 56 }
 57 void remove(node* &o,int val)
 58 {
 59     if(val==o->val)
 60     {
 61         if(o->ch[0]&&o->ch[1])
 62         {
 63             int d2=(o->ch[0]->rank > o->ch[1]->rank)?1:0;
 64             rotate(o,d2);remove(o->ch[d2],val);
 65         }
 66         else 
 67         {
 68             node* u=NULL;
 69             if(o->ch[0]!=NULL)u=o->ch[0];
 70             else u=o->ch[1];
 71             delete o;
 72             o=u;
 73         }
 74     }
 75     else 
 76         if(val< o->val)remove(o->ch[0],val);
 77         else remove(o->ch[1],val);
 78     if(o)o->tain();
 79 }
 80 inline int find_rank(node* o,int val)
 81 {
 82     int ge=0;
 83     while(o)
 84     {
 85         if(val> o->val)ge+=s(o->ch[0])+1,o=o->ch[1];
 86         else o=o->ch[0];
 87     }
 88     return ge;
 89 }
 90 int tree_rank(int le,int ri,int num,int val)
 91 {
 92     if(a<=le&&ri<=b)return find_rank(root[num],val);
 93     int mi=(le+ri)>>1;
 94     int ret=0;
 95     if(b<=mi)return tree_rank(le,mi,num<<1,val);
 96     if(mi<a)return tree_rank(mi+1,ri,(num<<1)|1,val);
 97     return tree_rank(le,mi,num<<1,val)+tree_rank(mi+1,ri,(num<<1)|1,val);
 98 }
 99 inline int divide_rank(int val)
100 {
101     int l=0,r=100000000;
102     while(l<=r)
103     {
104         int mi=(l+r)>>1;
105         int ans=tree_rank(1,n,1,mi)+1; 
106         if(ans<=val)l=mi+1;
107         else r=mi-1;
108     }
109     return r;
110 }
111 inline int pre(int le,int ri,int val)
112 {
113     int tmp=tree_rank(1,n,1,val);
114     return divide_rank(tmp);
115 }
116 inline int re(int le,int ri,int val)
117 {
118     int tmp=tree_rank(1,n,1,val+1)+1;
119     return divide_rank(tmp);
120 }
121 void change(int le,int ri,int num,int pos,int pre,int now)
122 {
123     remove(root[num],pre);
124     insert(root[num],now);
125     if(le==ri)return;
126     int mi=(le+ri)>>1;
127     if(pos<=mi)change(le,mi,num<<1,pos,pre,now);
128     else change(mi+1,ri,(num<<1)|1,pos,pre,now);
129 }
130 int main()
131 {
132     scanf("%d%d",&n,&m);
133     for(int i=1;i<=n;i++)
134         scanf("%d",&val[i]);
135     treeins(1,n,1);
136     while(m--)
137     {
138         scanf("%d",&o);
139         switch(o)
140         {
141             case 1:
142                 scanf("%d%d%d",&a,&b,&c);
143                 printf("%d\n",tree_rank(1,n,1,c)+1);break;
144             case 2:
145                 scanf("%d%d%d",&a,&b,&c);
146                 printf("%d\n",divide_rank(c));break;
147             case 3:
148                 scanf("%d%d",&a,&b);
149                 change(1,n,1,a,val[a],b);val[a]=b;break;
150             case 4:
151                 scanf("%d%d%d",&a,&b,&c);
152                 printf("%d\n",pre(a,b,c));break;
153             case 5:
154                 scanf("%d%d%d",&a,&b,&c);
155                 printf("%d\n",re(a,b,c));break;
156         }
157     }
158     //while(1);
159 }
BZOJ3196

相关文章:

  • 2022-12-23
  • 2021-06-06
  • 2021-11-19
  • 2021-12-02
  • 2021-12-09
  • 2021-08-26
  • 2021-06-04
猜你喜欢
  • 2022-01-06
  • 2022-12-23
  • 2022-12-23
  • 2022-01-18
相关资源
相似解决方案