zoukankan      html  css  js  c++  java
  • 树套树小结

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

    在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
    ",tree_rank(1,n,1,c)+1);break;
    144             case 2:
    145                 scanf("%d%d%d",&a,&b,&c);
    146                 printf("%d
    ",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
    ",pre(a,b,c));break;
    153             case 5:
    154                 scanf("%d%d%d",&a,&b,&c);
    155                 printf("%d
    ",re(a,b,c));break;
    156         }
    157     }
    158     //while(1);
    159 }
    BZOJ3196

    bzoj3262 陌上花开

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 const int N=100010,K=200010;
     6 int n,k,tot,bit[K];
     7 struct node
     8 {
     9     int a,b,c,val,id,ans;
    10     node(){val=ans=0;}
    11     inline void read(){scanf("%d%d%d",&a,&b,&c);}
    12     inline void print()
    13         {printf("a=%d b=%d c=%d val=%d id=%d
    ",a,b,c,val,id);}
    14 }q[N],tmp[N];
    15 int cnt[N],st[N];
    16 inline int lowbit(int a){return a&-a;}
    17 inline void add(int a,int val)
    18     {while(a<=k)bit[a]+=val,a+=lowbit(a);}
    19 inline int query(int a)
    20     {int ret=0;while(a)ret+=bit[a],a-=lowbit(a);return ret;}
    21 inline bool mt1(const node &a,const node &b)
    22 {
    23     if(a.a==b.a&&a.b==b.b)return a.c<b.c;
    24     return a.a==b.a?a.b<b.b:a.a<b.a;
    25 }
    26 inline bool mt2(const node &a,const node &b)
    27 {
    28     if(a.c==b.c&&a.b==b.b)return a.a<b.a;
    29     return a.b==b.b?a.c<b.c:a.b<b.b;
    30 }
    31 inline bool same(const node &a,const node &b)
    32     {return a.a==b.a&&a.b==b.b&&a.c==b.c;}
    33 inline void CDQ(int l,int r)
    34 {
    35     if(l==r){q[l].ans+=q[l].val-1;return;}
    36     register int i,mi=l+r>>1,l1=l,l2=mi+1;
    37     for(i=l;i<=r;++i)
    38         if(q[i].a<=mi)add(q[i].c,q[i].val);
    39         else q[i].ans+=query(q[i].c);
    40     for(i=l;i<=r;++i)
    41         if(q[i].a<=mi)add(q[i].c,-q[i].val);
    42     for(i=l;i<=r;++i)
    43         if(q[i].a<=mi)tmp[l1++]=q[i];
    44         else tmp[l2++]=q[i];
    45     for(i=l;i<=r;++i)q[i]=tmp[i];
    46     CDQ(l,mi),CDQ(mi+1,r);
    47 }
    48 int main()
    49 {
    50     register int i,j,sum;
    51     scanf("%d%d",&n,&k);sum=n;
    52     for(i=1;i<=n;++i)q[i].read(),q[i].val=1;
    53     sort(q+1,q+n+1,mt1);
    54     for(n=1,i=2;i<=sum;++i)
    55         if(same(q[i],q[n]))++q[n].val;
    56         else q[++n]=q[i];
    57     for(i=1;i<=n;++i)q[i].a=i;
    58     sort(q+1,q+n+1,mt2);
    59     CDQ(1,n);
    60     for(i=1;i<=n;++i)cnt[q[i].ans]+=q[i].val;
    61     for(i=0;i<sum;++i)printf("%d
    ",cnt[i]);
    62 }
    CDQ打法
      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <iostream>
      4 #include <algorithm>
      5 #include <cstring>
      6 using namespace std;
      7 char B[1<<15],*S=B,*T=B;
      8 #define getc ( (S==T&&( (T=(S=B)+fread(B,1,1<<15,stdin)),S==T) ) ?0:*S++ )
      9 inline int read()
     10 {
     11     int x=0;register char c=getc;
     12     while(c<'0'||c>'9')c=getc;
     13     while(c>='0'&&c<='9')x=10*x+(c^48),c=getc;
     14     return x;
     15 }
     16 #define N 100010
     17 #define K 200010
     18 struct flower{
     19     int a,b,c,ge;
     20     inline void init(){a=read(),b=read(),c=read(),ge=1;}
     21     inline bool operator == (const flower x) const
     22         {return a==x.a&&b==x.b&&c==x.c;}
     23 }f[N];
     24 inline bool mt(const flower &a,const flower &b)
     25 {
     26     if(a.a!=b.a)return a.a<b.a;
     27     return a.b==b.b?a.c<b.c:a.b<b.b;
     28 }
     29 int n,k,tota,totb,cnt[N];
     30 struct Treap
     31 {
     32     Treap *ch[2];
     33     int size,cnt,val,key;
     34     inline void update(){size=cnt+ch[0]->size+ch[1]->size;}
     35 }mema[N<<5],*null=new Treap();
     36 inline Treap* newTreap(int val=0,int size=0,int key=rand())
     37 {
     38     Treap *o=mema+(tota++);o->ch[0]=o->ch[1]=null;
     39     o->val=val,o->cnt=o->size=size,o->key=key;
     40     return o;
     41 }
     42 inline Treap* merge(Treap *a,Treap *b)
     43 {
     44     if(a==null)return b;
     45     if(b==null)return a;
     46     if(a->key > b->key)
     47         {a->ch[1]=merge(a->ch[1],b);a->update();return a;}
     48     else
     49         {b->ch[0]=merge(a,b->ch[0]);b->update();return b;}
     50 }
     51 #define D pair<Treap*,Treap*>
     52 inline D split(Treap *o,int val)
     53 {
     54     if(o==null)return D(null,null);
     55     D y;
     56     if(o->val>val)
     57         y=split(o->ch[0],val),o->ch[0]=y.second,o->update(),y.second=o;
     58     else 
     59         y=split(o->ch[1],val),o->ch[1]=y.first,o->update(),y.first=o;
     60     return y;
     61 }
     62 inline void insert(Treap *&o,flower p,int key)
     63 {
     64     if(o->key<key)
     65     {
     66         Treap *x=newTreap(p.c,p.ge,key);
     67         D y=split(o,p.c);
     68         x->ch[0]=y.first,x->ch[1]=y.second,x->update(),o=x;
     69         return;
     70     }
     71     if(o->val>p.c)insert(o->ch[0],p,key);
     72     else insert(o->ch[1],p,key);
     73     o->update();
     74 }
     75 inline int grs(Treap *o,int val)
     76 {
     77     if(o==null)return 0;
     78     return (o->val>val)?grs(o->ch[0],val):grs(o->ch[1],val)+o->ch[0]->size+o->cnt;
     79 }
     80 #define max(a,b) ((a)>(b)?(a):(b))
     81 #define min(a,b) ((a)<(b)?(a):(b))
     82 int maxb;
     83 struct node
     84 {
     85     Treap *alter;node *ch[2];
     86 }*root,memb[K<<1];
     87 inline node* build(int l,int r)
     88 {
     89     node *o=memb+(totb++);o->alter=null;
     90     if(l==r)return o;
     91     int mi=l+r>>1;
     92     o->ch[0]=build(l,mi);o->ch[1]=build(mi+1,r);
     93     return o;
     94 }
     95 inline void insert(node *&o,int l,int r,flower p)
     96 {
     97     insert(o->alter,p,rand());
     98     if(l==r)return;
     99     int mi=l+r>>1;
    100     if(p.b<=mi)insert(o->ch[0],l,mi,p);
    101     else insert(o->ch[1],mi+1,r,p);
    102 }
    103 inline int query(node *o,int l,int r,int L,int R,int val)
    104 {
    105     if(L<=l&&r<=R)return grs(o->alter,val);
    106     int mi=l+r>>1,ret=0;
    107     if(L<=mi)ret=query(o->ch[0],l,mi,L,R,val);
    108     if(mi<R)ret+=query(o->ch[1],mi+1,r,L,R,val);
    109     return ret;
    110 }
    111 inline void intn()
    112 {
    113     null=mema+(tota++),null->size=null->cnt=null->val=0;
    114     null->key=-1;null->ch[0]=null->ch[1]=null;
    115     root=build(1,maxb);
    116 }
    117 int main()
    118 {
    119     register int i,sum;
    120     n=read(),k=read();
    121     for(i=1;i<=n;++i)f[i].init(),maxb=max(maxb,f[i].b);
    122     sort(f+1,f+n+1,mt);intn();
    123     for(sum=n,n=1,i=2;i<=sum;++i)
    124         if(f[i]==f[n])++f[n].ge;
    125         else f[++n]=f[i];
    126     for(i=1;i<=n;++i)
    127         insert(root,1,maxb,f[i]),
    128         cnt[query(root,1,maxb,1,f[i].b,f[i].c)-1]+=f[i].ge;
    129     for(i=0;i<sum;++i)printf("%d
    ",cnt[i]);
    130 }
    树套树打法

    bzoj3295 动态逆序对

     1 #include <cstring>
     2 #include <cstdio>
     3 #include <algorithm>
     4 using namespace std;
     5 typedef long long LL;
     6 const int N=100010,M=50010;
     7 struct node
     8 {
     9     int tim,val,pos;
    10     node (int a=0,int b=0,int c=0){tim=a,val=b,pos=c;}
    11 }q[N];
    12 int cnt,n,m,a[N],match[N],step[M];
    13 bool vis[N];
    14 LL delta[2][N],num[2][N],bit[N];
    15 inline int lowbit(int a){return a&-a;}
    16 inline void add(int a,LL b)
    17     {while(a<=n)bit[a]+=b,a+=lowbit(a);}
    18 inline LL sum(int a)
    19     {LL ret=0;while(a)ret+=bit[a],a-=lowbit(a);return ret;}
    20 inline void gsum0()
    21 {
    22     for(register int i=1;i<=n;++i)
    23         num[0][i]=sum(a[i]),add(a[i],1);
    24     memset(bit,0,sizeof(bit));
    25 }
    26 inline void gsum1()
    27 {
    28     for(register int i=n;i;--i)
    29         num[1][i]=sum(a[i]),add(1,1),add(a[i],-1);
    30     memset(bit,0,sizeof(bit));
    31 }
    32 inline void readin()
    33 {
    34     register int i;scanf("%d%d",&n,&m);
    35     for(i=1;i<=n;++i)
    36         scanf("%d",&a[i]),a[i]=n-a[i]+1,match[a[i]]=i;
    37     gsum0();gsum1();
    38     for(i=1;i<=m;++i)
    39         scanf("%d",&step[i]),step[i]=n-step[i]+1,vis[step[i]]=1;
    40 }
    41 inline bool mt1(const node &a,const node &b){return a.pos<b.pos;}
    42 inline bool mt2(const node &a,const node &b){return a.tim<b.tim;}
    43 inline void CDQ0(int l,int r)
    44 {
    45     if(l==r)return;
    46     register int mi=l+r>>1,i;
    47     CDQ0(l,mi);CDQ0(mi+1,r);
    48     sort(q+l,q+r+1,mt1);
    49     for(i=l;i<=r;++i)
    50         if(q[i].tim<=mi)add(q[i].val,1);
    51         else delta[0][q[i].tim]+=sum(q[i].val);
    52     for(i=l;i<=r;++i)
    53         if(q[i].tim<=mi)add(q[i].val,-1);
    54 }
    55 inline void CDQ1(int l,int r)
    56 {
    57     if(l==r)return;
    58     register int mi=l+r>>1,i;
    59     CDQ1(l,mi);CDQ1(mi+1,r);
    60     sort(q+l,q+r+1,mt1);
    61     for(i=r;i>=l;--i)
    62         if(q[i].tim<=mi)add(1,1),add(q[i].val,-1);
    63         else delta[1][q[i].tim]+=sum(q[i].val);
    64     for(i=r;i>=l;--i)
    65         if(q[i].tim<=mi)add(1,-1),add(q[i].val,1);
    66 }
    67 int main()
    68 {
    69     register int i;readin();
    70     for(i=1;i<=m;++i)
    71         q[++cnt]=node(cnt,step[i],match[step[i]]);
    72     for(i=1;i<=n;++i)
    73         if(!vis[a[i]])q[++cnt]=node(cnt,a[i],i);
    74     CDQ0(1,n),sort(q+1,q+n+1,mt2),CDQ1(1,n);
    75     LL ans=0;int pos;
    76     for(i=1;i<=n;++i)ans+=num[0][i];
    77     for(i=1;i<=m;++i)
    78     {
    79         printf("%lld
    ",ans),pos=match[step[i]],
    80         ans-=(num[0][pos]+num[1][pos]),
    81         ans+=(delta[0][i]+delta[1][i]);
    82     }
    83 }
    CDQ打法
      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <iostream>
      4 #include <cstring>
      5 using namespace std;
      6 #define N 100010
      7 int n,m,tota,totb;
      8 int a[N],b[N],tmp[N];
      9 #define LL long long
     10 LL ans;
     11 struct Treap
     12 {
     13     int val,size,key;Treap *ch[2];
     14     Treap(){ch[0]=ch[1]=NULL;val=size=0;}
     15     inline void update(){size=ch[0]->size+1+ch[1]->size;}
     16 }mema[N<<5],*null=new Treap();
     17 inline Treap* newTreap(int val=0,int key=rand())
     18 {
     19     Treap *o=mema+(tota++);
     20     o->ch[0]=o->ch[1]=null;
     21     o->key=key;o->val=val;
     22     o->size=1;return o;
     23 }
     24 inline Treap* merge(Treap* a,Treap* b)
     25 {
     26     if(a==null)return b;
     27     if(b==null)return a;
     28     if(a->key > b->key) {a->ch[1]=merge(a->ch[1],b);a->update();return a;}
     29     else {b->ch[0]=merge(a,b->ch[0]),b->update();return b;}
     30 }
     31 #define D pair<Treap*,Treap*>
     32 inline D split1(Treap *o,int k)
     33 {
     34     if(o==null)return D(null,null);
     35     D y;
     36     if(o->ch[0]->size>=k)
     37         y=split1(o->ch[0],k),o->ch[0]=y.second,o->update(),y.second=o;
     38     else 
     39         y=split1(o->ch[1],k-o->ch[0]->size-1),o->ch[1]=y.first,o->update(),y.first=o;
     40     return y;
     41 }
     42 inline D split2(Treap *o,int val)
     43 {
     44     if(o==null)return D(null,null);
     45     D y;
     46     if(o->val>=val)
     47         y=split2(o->ch[0],val),o->ch[0]=y.second,o->update(),y.second=o;
     48     else 
     49         y=split2(o->ch[1],val),o->ch[1]=y.first,o->update(),y.first=o;
     50     return y;
     51 }
     52 inline void del(Treap *&o,int val)
     53 {
     54     if(o==null)return;
     55     if(o->val>val)del(o->ch[0],val);
     56     else if(o->val==val){o=merge(o->ch[0],o->ch[1]);return;}
     57     else del(o->ch[1],val);
     58     o->update();
     59 }
     60 inline void insert(Treap *&o,int val,int key)
     61 {
     62     if(o->key<key)
     63     {
     64         Treap *x=newTreap(val,key);
     65         D y=split2(o,val);
     66         x->ch[0]=y.first,x->ch[1]=y.second;
     67         x->update(),o=x;
     68         return;
     69     }
     70     else if(o->val>=val)insert(o->ch[0],val,key);
     71     else insert(o->ch[1],val,key);
     72     o->update();
     73 }
     74 inline int grb(Treap *o,int val)
     75 {
     76     if(o==null)return 0;
     77     return (o->val<=val)?grb(o->ch[1],val):(grb(o->ch[0],val)+o->ch[1]->size+1);
     78 }
     79 inline int grs(Treap *o,int val)
     80 {
     81     if(o==null)return 0;
     82     return (o->val>=val)?grs(o->ch[0],val):(grs(o->ch[1],val)+o->ch[0]->size+1);
     83 }
     84 struct node
     85 {
     86     Treap *summa;node *ch[2];
     87     node(){ch[0]=ch[1]=NULL;}
     88 }memb[N<<1],*root;
     89 inline node* build(int l,int r)
     90 {
     91     node *o=memb+(totb++);o->summa=null;
     92     if(l==r)return o;
     93     int mi=l+r>>1;
     94     o->ch[0]=build(l,mi),o->ch[1]=build(mi+1,r);
     95     return o;
     96 }
     97 inline int queryl(node *o,int l,int r,int L,int R,int val)
     98 {
     99     if(L<=l&&r<=R)return grb(o->summa,val);
    100     int mi=l+r>>1,ret=0;
    101     if(L<=mi)ret=queryl(o->ch[0],l,mi,L,R,val);
    102     if(mi<R)ret+=queryl(o->ch[1],mi+1,r,L,R,val);
    103     return ret;
    104 }
    105 inline int queryr(node *o,int l,int r,int L,int R,int val)
    106 {
    107     if(L<=l&&r<=R)return grs(o->summa,val);
    108     int mi=l+r>>1,ret=0;
    109     if(L<=mi)ret=queryr(o->ch[0],l,mi,L,R,val);
    110     if(mi<R)ret+=queryr(o->ch[1],mi+1,r,L,R,val);
    111     return ret;
    112 }
    113 inline void insert(node *o,int l,int r,int pos,int val)
    114 {
    115     insert(o->summa,val,rand());
    116     if(l==r)return;
    117     int mi=l+r>>1;
    118     if(pos<=mi)insert(o->ch[0],l,mi,pos,val);
    119     else insert(o->ch[1],mi+1,r,pos,val);
    120 }
    121 inline void del(node *o,int l,int r,int pos,int val)
    122 {
    123     del(o->summa,val);
    124     if(l==r)return;
    125     int mi=l+r>>1;
    126     if(pos<=mi)del(o->ch[0],l,mi,pos,val);
    127     else del(o->ch[1],mi+1,r,pos,val);
    128 }
    129 inline void get_base(int l,int r)
    130 {
    131     if(l==r)return;
    132     int mi=l+r>>1,p=l,q=mi+1,h=l;
    133     get_base(l,mi),get_base(mi+1,r);
    134     while(p<=mi&&q<=r)
    135         if(a[p]<a[q])tmp[h++]=a[p++];
    136         else ans+=(mi-p+1),tmp[h++]=a[q++];
    137     while(p<=mi)tmp[h++]=a[p++];
    138     while(q<=r)tmp[h++]=a[q++];
    139     for(int i=l;i<=r;++i)a[i]=tmp[i];
    140 }
    141 char B[1<<15],*S=B,*T=B;
    142 #define getc ( S==T&& (T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++ )
    143 inline int read()
    144 {
    145     int x=0;register char c=getc;
    146     while(c<'0'||c>'9')c=getc;
    147     while(c>='0'&&c<='9')x=10*x+(c^48),c=getc;
    148     return x;
    149 }
    150 int main()
    151 {
    152     register int i,j;
    153     null->ch[0]=null->ch[1]=null,null->key=-0x7fffffff;
    154     n=read(),m=read(),root=build(1,n);
    155     for(i=1;i<=n;++i)a[i]=read(),insert(root,1,n,i,a[i]);
    156     memcpy(b,a,sizeof(a));
    157     get_base(1,n);
    158     for(i=1;i<=n;++i)tmp[b[i]]=i;
    159     while(m--)
    160         i=read(),j=tmp[i],printf("%lld
    ",ans),
    161         ans-=queryl(root,1,n,1,j,i)+queryr(root,1,n,j,n,i),
    162         del(root,1,n,j,i);
    163 }
    树套树打法

    bzoj2141 排队(和上面那题差不多,就不附代码了)

    这些题没有太大的难度,直接按照题意操作即可~


    二.线段树/树状数组套权值线段树

    如果是套线段树,就是我们常说的“树状数组套主席树”了。

    其实这里的内层线段树并不是主席树,而是很多颗权值线段树.

    这样套的好处就是让原本静态的主席树变得可以支持修改,因为每次修改只会更改logn级别棵内层树的信息

    线段树依然有区间加减性,因此对于某一个给定区间我们可以用log棵权值线段树通过加减来“拼”出对应区间的线段树

    所以每一种操作都是$O(nlog2n)$的.

    这类树套树的习题有:

    bzoj4009 接水果(模型转换之后整体二分or线段树套线段树)

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 using namespace std;
      5 #define inf 1000000000
      6 #define N 40010
      7 int tot,cnt,n,p,q,e,adj[N];
      8 struct edge{int zhong,next;}s[N<<1];
      9 inline void add(int qi,int zhong)
     10     {s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;}
     11 char B[1<<15],*S=B,*T=B;
     12 #define getc ( S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++ )
     13 inline int read()
     14 {
     15     int x=0;register char c=getc;
     16     while(c<'0'||c>'9')c=getc;
     17     while(c>='0'&&c<='9')x=10*x+(c^48),c=getc;
     18     return x;
     19 }
     20 int f[N][16],bin[25],tp,deep[N];
     21 int st[N],ed[N],val[N],l[N],r[N],num;
     22 inline void mission1(int rt)
     23     {for(int i=1;i<=tp;++i)f[rt][i]=f[f[rt][i-1]][i-1];}
     24 inline int LCA(int a,int b)
     25 {
     26     if(deep[a]<deep[b])a^=b,b^=a,a^=b;
     27     register int i,cha=deep[a]-deep[b];
     28     for(i=tp;~i;--i)if(cha&bin[i])a=f[a][i];
     29     if(a==b)return a;
     30     for(i=tp;~i;--i)
     31         if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
     32     return f[a][0];
     33 }
     34 inline int gonear(int a,int b)
     35 {
     36     register int i,cha=deep[a]-deep[b]-1;
     37     for(i=tp;~i;--i)if(cha&bin[i])a=f[a][i];
     38     return a;
     39 }
     40 inline void dfs1(int rt,int fa)
     41 {
     42     f[rt][0]=fa,deep[rt]=deep[fa]+1;
     43     l[rt]=++num,mission1(rt);
     44     for(int i=adj[rt];i;i=s[i].next)
     45         if(s[i].zhong!=fa)dfs1(s[i].zhong,rt);
     46     r[rt]=num;
     47 }
     48 int ans[N],sum[N],bit[N];
     49 #define lowbit(i) ((i)&(-(i)))
     50 inline void update(int l,int r,int val)
     51 {
     52     for(int i=l;i<=n;i+=lowbit(i))bit[i]+=val;
     53     for(int i=r+1;i<=n;i+=lowbit(i))bit[i]-=val;
     54 }
     55 inline int query(int i)
     56 {
     57     int ret=0;
     58     for(;i>0;i-=lowbit(i))ret+=bit[i];
     59     return ret;
     60 }
     61 struct plate{int x1,x2,y1,y2,val;}pl[N<<1];
     62 struct fruit{int x,y,k,id;}fr[N],tmp1[N],tmp2[N];
     63 struct node{int x,y1,y2,val,id;}eve[N*5];
     64 inline bool mt(const plate &a,const plate &b){return a.val<b.val;}
     65 inline bool mt2(const node &a,const node &b){return a.x==b.x?a.id<b.id:a.x<b.x;}
     66 inline void get_ans(int le,int ri,int L,int R)
     67 {
     68     if(L>R)return;
     69     if(le==ri)
     70     {
     71         for(int i=L;i<=R;++i)ans[fr[i].id]=pl[le].val;
     72         return;
     73     }
     74     int a=0,b=0,mi=le+ri>>1;tot=0;
     75     for(int i=le;i<=mi;++i)
     76         eve[++tot]=(node){pl[i].x1,pl[i].y1,pl[i].y2,1,0},
     77         eve[++tot]=(node){pl[i].x2,pl[i].y1,pl[i].y2,-1,q+1};
     78     for(int i=L;i<=R;++i)
     79         eve[++tot]=(node){fr[i].x,fr[i].y,0,0,i};
     80     sort(eve+1,eve+tot+1,mt2);
     81     for(int i=1;i<=tot;++i)
     82         if(L<=eve[i].id&&eve[i].id<=R)sum[eve[i].id]=query(eve[i].y1);
     83         else update(eve[i].y1,eve[i].y2,eve[i].val);
     84     for(int i=L;i<=R;++i)
     85         if(sum[i]>=fr[i].k)tmp1[++a]=fr[i];
     86         else tmp2[++b]=fr[i],tmp2[b].k-=sum[i];
     87     for(int i=1;i<=a;++i)fr[i+L-1]=tmp1[i];
     88     for(int i=1;i<=b;++i)fr[i+L+a-1]=tmp2[i];
     89     get_ans(le,mi,L,L+a-1),get_ans(mi+1,ri,L+a,R);
     90 }
     91 int main()
     92 {
     93     register int i,j,a,b,c,lca,x;
     94     n=read(),p=read(),q=read();
     95     for(i=bin[0]=1;i<=20;++i)bin[i]=bin[i-1]<<1;
     96     while(bin[tp+1]<=n)++tp;
     97     for(i=1;i<n;++i)a=read(),b=read(),add(a,b),add(b,a);
     98     dfs1(1,0);
     99     for(i=1;i<=p;++i)
    100     {
    101         a=read(),b=read(),c=read(),lca=LCA(a,b);
    102         if(l[a]>l[b])a^=b,b^=a,a^=b;
    103         if(a!=lca)
    104             pl[++cnt]=(plate){l[a],r[a],l[b],r[b],c};
    105         else
    106         {
    107             x=gonear(b,a);
    108             if(l[x]>1)pl[++cnt]=(plate){1,l[x]-1,l[b],r[b],c};
    109             if(r[x]<n)pl[++cnt]=(plate){l[b],r[b],r[x]+1,n,c};
    110         }
    111     }
    112     for(i=1;i<=q;++i)
    113     {
    114         a=read(),b=read(),c=read();
    115         if(l[a]>l[b])a^=b,b^=a,a^=b;
    116         fr[i]=(fruit){l[a],l[b],c,i};
    117     }
    118     sort(pl+1,pl+cnt+1,mt),get_ans(1,cnt,1,q);
    119     for(i=1;i<=q;++i)printf("%d
    ",ans[i]);
    120 }
    整体二分

    (没打树套树……懒了233)

    bzoj1146 网络管理Network(树状数组套主席树上树)

      1 #include <cstdio>
      2 #include <cstring>
      3 using namespace std;
      4 #define N 80010
      5 #define inf 100000000
      6 char B[1<<15],*S=B,*T=B;
      7 #define GG puts("invalid request!")
      8 #define getc ( S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T) ?0:*S++ )
      9 inline int read()
     10 {
     11     int x=0;register char c=getc;
     12     while(c<'0'||c>'9')c=getc;
     13     while(c>='0'&&c<='9')x=10*x+(c^48),c=getc;
     14     return x;
     15 }
     16 int n,e=0,adj[N],t[N],tot,m;
     17 struct edge{int zhong,next;}s[N<<1];
     18 inline void add(int qi,int zhong)
     19     {s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;}
     20 #define lowbit(a) ((a)&(-(a)))
     21 int num,l[N],r[N];
     22 struct node
     23 {
     24     node *ch[2];int size;
     25     node(){ch[0]=ch[1]=NULL;size=0;}
     26 }*root[N<<1],mem[(N<<8)+10],*null,*stacka[1010],*stackb[1010];
     27 inline void insert(node *&o,int l,int r,int pos,int val)
     28 {
     29     if(o==null)
     30         o=mem+(tot++),o->size=0,o->ch[0]=o->ch[1]=null;
     31     o->size+=val;if(l==r)return;
     32     int mi=l+r>>1;
     33     if(pos<=mi)insert(o->ch[0],l,mi,pos,val);
     34     else insert(o->ch[1],mi+1,r,pos,val);
     35 }
     36 inline void insert(int id,int val,int opt)
     37 {
     38     while(id<=m)
     39         insert(root[id],0,inf,val,opt),id+=lowbit(id);
     40 }
     41 int f[N][17],bin[25],tp,deep[N],cnta,cntb;
     42 inline void mission1(int rt)
     43     {for(int i=1;i<=tp;++i)f[rt][i]=f[ f[rt][i-1] ][i-1];}
     44 inline void dfs1(int rt,int fa)
     45 {
     46     f[rt][0]=fa,deep[rt]=deep[fa]+1;mission1(rt);
     47     l[rt]=++num,insert(l[rt],t[rt],1);
     48     for(int i=adj[rt];i;i=s[i].next)
     49         if(s[i].zhong!=fa)dfs1(s[i].zhong,rt);
     50     r[rt]=++num,insert(r[rt]+1,t[rt],-1);
     51 }
     52 inline void intn()
     53 {
     54     null=new node(),null->size=0,null->ch[0]=null->ch[1]=null;
     55     for(int i=0;i<=m;++i)root[i]=null;
     56     dfs1(1,0);
     57 }
     58 inline int LCA(int a,int b)
     59 {   
     60     if(deep[a]<deep[b])a^=b,b^=a,a^=b;
     61     int cha=deep[a]-deep[b];
     62     for(int i=tp;~i;--i)if(cha&bin[i])a=f[a][i];
     63     if(a==b)return a;
     64     for(int i=tp;~i;--i)
     65         if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
     66     return f[a][0];
     67 }
     68 inline void get(int id,int opt)
     69 {
     70     while(id>0)
     71     {
     72         if(opt==1)stacka[++cnta]=root[id];
     73         else stackb[++cntb]=root[id];
     74         id-=lowbit(id);
     75     }
     76 }
     77 inline int query(int le,int ri,int k)
     78 {
     79     if(le==ri)return le;
     80     register int i,mi=le+ri>>1,sum=0;
     81     for(i=1;i<=cnta;++i)sum+=stacka[i]->ch[1]->size;
     82     for(i=1;i<=cntb;++i)sum-=stackb[i]->ch[1]->size;
     83     if(sum>=k)
     84     {
     85         for(i=1;i<=cnta;++i)stacka[i]=stacka[i]->ch[1];
     86         for(i=1;i<=cntb;++i)stackb[i]=stackb[i]->ch[1];
     87         return query(mi+1,ri,k);
     88     }
     89     else
     90     {
     91         for(i=1;i<=cnta;++i)stacka[i]=stacka[i]->ch[0];
     92         for(i=1;i<=cntb;++i)stackb[i]=stackb[i]->ch[0];
     93         return query(le,mi,k-sum);
     94     }
     95 }
     96 inline void get_ans(int le,int ri,int k)
     97 {
     98     int lca=LCA(le,ri);
     99     if(k> deep[le]+deep[ri]- (deep[lca]<<1) +1 ){GG;return;}
    100     cnta=cntb=0,
    101     get(l[le],1),get(l[lca],-1),
    102     get(l[ri],1),get(l[f[lca][0]],-1);
    103     printf("%d
    ",query(0,inf,k));
    104 }
    105 inline void change(int pos,int val)
    106 {
    107     insert(l[pos],t[pos],-1),insert(r[pos]+1,t[pos],1),t[pos]=val,
    108     insert(l[pos],val,1),insert(r[pos]+1,val,-1);
    109 }
    110 int main()
    111 {
    112     register int i,j,q,a,b,opt;
    113     n=read(),q=read(),m=n<<1;
    114     for(bin[0]=i=1;i<=20;++i)bin[i]=bin[i-1]<<1;
    115     while(bin[tp+1]<=n)++tp;
    116     for(i=1;i<=n;++i)t[i]=read();
    117     for(i=1;i<n;++i)
    118         a=read(),b=read(),add(a,b),add(b,a);
    119     intn();
    120     while(q--)
    121     {
    122         opt=read(),a=read(),b=read();
    123         if(opt)get_ans(a,b,opt);
    124         else change(a,b);
    125     }
    126 }
    BZOJ1146

    三.平衡树套权值线段树/平衡树

    这大概是比较高端的一种套法?

    有的时候我们会发现线段树无法胜任套在外面这个要求,比如一个常见的原因是区间长度固定,无法支持区间内的插入。

    那么我们就需要外层的数据结构是平衡树了:平衡树可以在中间插入。

    并且这树还不能旋转,由于旋转带来的父子关系改变带来的维护会耗费大量的时间。

    那么我们的选择只剩下替罪羊树和无旋Treap了。

    我们一般使用替罪羊树而不是无旋Treap,因为无旋Treap常数大,并且在split和merge时的信息维护也很慢……

    在实际编程时,我们就正常的插入,在替罪羊的节点对应的内层树中插入新点的权值,后面的查询操作根据题意而定。

    只要没有玩脱这些操作的复杂度也都是$O(nlog2n)$的。

    这种类型的题目有:

    bzoj3065 带插入区间k小值 (替罪羊套权值线段树,操作的时候和树状数组套线段树差不多,提取出通过加减可以表达对应区间的根节点组,然后找到答案。)

      1 #include <cstdio>
      2 #include <cstring>
      3 using namespace std;
      4 #define N 70010
      5 #define MAXN 70000
      6 int n,a[N];
      7 char B[1<<15],*S=B,*T=B,X=0;
      8 #define getc ( S==T && ( T=(S=B)+fread(B,1,1<<15,stdin), S==T) ? 0: *S++ )
      9 inline int read()
     10 {
     11     int x=0;
     12     while(X<'0'||X>'9')X=getc;
     13     while(X>='0'&&X<='9')x=10*x+(X^48),X=getc;
     14     return x;
     15 }
     16 inline char readc(){while(X<'A'||X>'Z')X=getc;return X;}
     17 int topa,topb,top,cnta,cntb;
     18 struct node
     19 {
     20     node* ch[2];int size;
     21     node(){size=0,ch[0]=ch[1]=NULL;}
     22 }*NIL=new node(),mem[(N<<8)+10],*pool[(N<<8)+10],*stacka[510],*stackb[510];
     23 inline void dfs2(node *o)
     24 {
     25     if(o==NIL)return;
     26     if(o->ch[0]!=NIL)dfs2(o->ch[0]);
     27     if(o->ch[1]!=NIL)dfs2(o->ch[1]);
     28     o->size=0,o->ch[0]=o->ch[1]=NIL,pool[++topa]=o;
     29 }
     30 inline void insert(node *&o,int l,int r,int pos)
     31 {
     32     if(o==NIL)o=pool[topa--],o->size=0,o->ch[0]=o->ch[1]=NIL;
     33     ++o->size;
     34     if(l<r)
     35     {
     36         int mi=l+r>>1;
     37         if(pos<=mi)insert(o->ch[0],l,mi,pos);
     38         else insert(o->ch[1],mi+1,r,pos);
     39     }
     40 }
     41 inline void del(node *&o,int l,int r,int pos)
     42 {
     43     --o->size;
     44     if(l<r)
     45     {
     46         int mi=l+r>>1;
     47         if(pos<=mi)del(o->ch[0],l,mi,pos);
     48         else del(o->ch[1],mi+1,r,pos);
     49     }
     50     if(o->size==0)
     51         pool[++topa]=o,o=NIL;
     52 }
     53 inline int get_ans(int l,int r,int k)
     54 {
     55     if(l==r)return l;
     56     register int i,sum=0,mi=l+r>>1;
     57     for(i=1;i<=cnta;++i)
     58         sum+=stacka[i]->ch[0]->size;
     59     for(i=1;i<=cntb;++i)
     60         sum-=stackb[i]->ch[0]->size;
     61     if(sum>=k)
     62     {
     63         for(i=1;i<=cnta;++i)stacka[i]=stacka[i]->ch[0];
     64         for(i=1;i<=cntb;++i)stackb[i]=stackb[i]->ch[0];
     65         return get_ans(l,mi,k);
     66     }
     67     else
     68     {
     69         for(i=1;i<=cnta;++i)stacka[i]=stacka[i]->ch[1];
     70         for(i=1;i<=cntb;++i)stackb[i]=stackb[i]->ch[1];
     71         return get_ans(mi+1,r,k-sum);
     72     }
     73 }
     74 #define alpha 0.755
     75 struct Goat
     76 {
     77     Goat *ch[2];node *tree;
     78     int size,val;
     79     inline bool bad()
     80         {return ch[0]->size>=size*alpha+5 ||ch[1]->size>=size*alpha+5;}
     81     inline void update()
     82         {size=ch[0]->size+1+ch[1]->size;}
     83 }*root,*null,memGoat[(N<<2)+10],*poolGoat[(N<<2)+10],*stackc[(N<<2)+10];
     84 inline Goat** insert(Goat *&o,int pos,int val)
     85 {
     86     int to=(o->ch[0]->size+1 < pos)?1:0;
     87     ++o->size,insert(o->tree,0,MAXN,val);
     88     if(o->ch[to]==null)
     89     {
     90         o->ch[to]=poolGoat[topb--];
     91         o->ch[to]->ch[0]=o->ch[to]->ch[1]=null;
     92         o->ch[to]->val=val;
     93         o->ch[to]->size=1;
     94         o->ch[to]->tree=NIL;
     95         insert(o->ch[to]->tree,0,MAXN,val);
     96         return &null;
     97     }
     98     Goat **ret=insert(o->ch[to],pos-(o->ch[0]->size+1)*to,val);
     99     if(o->bad())ret=&o;
    100     return ret;
    101 }
    102 inline int change(Goat *o,int pos,int val)
    103 {
    104     insert(o->tree,0,MAXN,val);
    105     if(o->ch[0]->size+1==pos)
    106     {
    107         int ret=o->val;
    108         del(o->tree,0,MAXN,o->val),o->val=val;
    109         return ret;
    110     }
    111     int ret;
    112     if(o->ch[0]->size >= pos)ret=change(o->ch[0],pos,val);
    113     else ret=change(o->ch[1],pos-o->ch[0]->size-1,val);
    114     del(o->tree,0,MAXN,ret);return ret;
    115 }
    116 inline void get_l(Goat *o,int l)
    117 {
    118     if(o==null)return;
    119     if(o->ch[0]->size>=l)
    120     {
    121         stacka[++cnta]=o->tree,stackb[++cntb]=o->ch[0]->tree,
    122         get_l(o->ch[0],l);
    123     }
    124     else if(o->ch[0]->size+1==l)
    125     {
    126         stacka[++cnta]=o->tree,stackb[++cntb]=o->ch[0]->tree;
    127     }
    128     else
    129         get_l(o->ch[1],l-o->ch[0]->size-1);
    130 }
    131 inline void get_r(Goat *o,int r)
    132 {
    133     if(o==null)return;
    134     if(o->ch[0]->size>=r)
    135         get_r(o->ch[0],r);
    136     else if(o->ch[0]->size+1==r)
    137     {
    138         stacka[++cnta]=o->tree,stackb[++cntb]=o->ch[1]->tree;
    139     }
    140     else
    141     {
    142         stacka[++cnta]=o->tree,stackb[++cntb]=o->ch[1]->tree;
    143         get_r(o->ch[1],r-o->ch[0]->size-1);
    144     }
    145 }
    146 inline void dfs(Goat *o)
    147 {
    148     if(o==null)return;
    149     if(o->ch[0]!=null)dfs(o->ch[0]);
    150     stackc[++top]=o,dfs2(o->tree);
    151     if(o->ch[1]!=null)dfs(o->ch[1]);
    152 }
    153 inline void onboard(Goat *o,node *&x)
    154 {
    155     if(o==null)return;
    156     if(o->ch[0]!=null)onboard(o->ch[0],x);
    157     insert(x,0,MAXN,o->val);
    158     if(o->ch[1]!=null)onboard(o->ch[1],x);
    159 }
    160 inline Goat* build(int l,int r)
    161 {
    162     if(l>r)return null;
    163     int mi=l+r>>1;
    164     stackc[mi]->size=r-l+1;
    165     stackc[mi]->ch[0]=build(l,mi-1),stackc[mi]->ch[1]=build(mi+1,r);
    166     stackc[mi]->tree=pool[topa--];stackc[mi]->tree->size=0;
    167     stackc[mi]->tree->ch[0]=stackc[mi]->tree->ch[1]=NIL;
    168     onboard(stackc[mi]->ch[0],stackc[mi]->tree);
    169     onboard(stackc[mi]->ch[1],stackc[mi]->tree);
    170     insert(stackc[mi]->tree,0,MAXN,stackc[mi]->val);
    171     return stackc[mi];
    172 }
    173 inline void rebuild(Goat *&o)
    174 {
    175     top=0;dfs(o);
    176     o=build(1,top);
    177 }
    178 inline void intn()
    179 {
    180     NIL->ch[0]=NIL->ch[1]=NIL;NIL->size=0;
    181     null=new Goat();null->tree=NIL;
    182     null->size=null->val=0;
    183     null->ch[0]=null->ch[1]=null;
    184     topa=topb=0;
    185     for(topa=0;topa<(N<<8);++topa)
    186         pool[topa]=mem+topa,pool[topa]->size=0,
    187         pool[topa]->ch[0]=pool[topa]->ch[1]=NIL;
    188     for(topb=0;topb<(N<<2);++topb)
    189         poolGoat[topb]=memGoat+topb,poolGoat[topb]->size=0,
    190         poolGoat[topb]->ch[0]=poolGoat[topb]->ch[1]=null;
    191     topa=(N<<8)-1,topb=(N<<2)-1;
    192     for(int i=1;i<=n;++i)
    193         stackc[i]=poolGoat[topb--],stackc[i]->val=a[i];
    194     root=build(1,n);
    195 }
    196 int main()
    197 {
    198     register int i,j,q,ans=0,l,r,x;char opt;Goat **p7;
    199     n=read();for(i=1;i<=n;++i)a[i]=read();
    200     intn(),q=read();
    201     for(i=1;i<=q;++i)
    202     {
    203         opt=readc();
    204         switch(opt)
    205         {
    206             case 'Q':
    207                 l=read()^ans,r=read()^ans,x=read()^ans;
    208                 cnta=cntb=0,get_l(root,l),get_r(root,r);
    209                 stackb[++cntb]=root->tree;
    210                 printf("%d
    ",(ans=get_ans(0,MAXN,x)) );
    211                 break;
    212             case 'M':
    213                 l=read()^ans,x=read()^ans;
    214                 change(root,l,x);
    215                 break;
    216             case 'I':
    217                 l=read()^ans,x=read()^ans;
    218                 p7=insert(root,l,x);
    219                 if(*p7!=null)rebuild(*p7);
    220                 break;
    221         }
    222     }
    223 }
    BZOJ3065

    bzoj3217 ALOEXT(替罪羊套Trie树,和上面类似)

    (还没打……明天补坑)

    *PS:替罪羊树的思想是很好的,这种重建的思想可以优化很多题目的复杂度。


    四.树套树在DP题目中的运用

    有一些DP题目的转移会涉及到多维的取值关系,因此我们可以用树套树处理这类题目

    我们依然用一种数据结构维护一维,在最内层的数据结构中维护对应的DP有关变量。

    当然CDQ也可以干这事啦!

    这种类型的题目有:

    bzoj4553 序列

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 const int N=300000;
     7 int n,m,bit[N+100],f[N+100];
     8 struct num{int val,maxv,minv;}x[N+100];
     9 struct cdq{int x,y,id;}a[N+100];
    10 inline int lowbit(int a){return a&(-a);}
    11 inline bool mt(const cdq &a,const cdq &b)
    12 {return (a.x==b.x)?a.id<b.id:a.x<b.x;}
    13 inline void add(int i,int val)
    14 {
    15     while(i<=N)
    16     {
    17         bit[i]=(val==0)?0:max(bit[i],val);
    18         i+=lowbit(i);
    19     }
    20 }
    21 inline int sum(int i)
    22 {
    23     int ret=0;
    24     while(i)
    25         ret=max(ret,bit[i]),i-=lowbit(i);
    26     return ret;
    27 }
    28 void cdq(int l,int r)
    29 {
    30     if(l==r){f[l]=max(f[l],1);return;}
    31     int mi=(l+r)>>1;
    32     cdq(l,mi);
    33     for(int i=l;i<=r;i++)
    34     {
    35         if(i<=mi)a[i].x=x[i].val,a[i].y=x[i].maxv;
    36         else a[i].x=x[i].minv,a[i].y=x[i].val;
    37         a[i].id=i;
    38     }
    39     sort(a+l,a+r+1,mt);
    40     for(int i=l;i<=r;i++)
    41     {
    42         if(a[i].id<=mi)add(a[i].y,f[a[i].id]);
    43         else f[a[i].id]=max(sum(a[i].y)+1,f[a[i].id]);
    44     }
    45     for(int i=l;i<=r;i++)add(a[i].y,0);
    46     cdq(mi+1,r);
    47 }
    48 int main()
    49 {
    50     scanf("%d%d",&n,&m);int u,v,ans=0;
    51     for(int i=1;i<=n;i++)
    52         scanf("%d",&x[i].val),x[i].minv=x[i].maxv=x[i].val;
    53     while(m--)
    54     {
    55         scanf("%d%d",&u,&v);
    56         x[u].maxv=max(x[u].maxv,v);
    57         x[u].minv=min(x[u].minv,v);
    58     }
    59     cdq(1,n);
    60     for(int i=1;i<=n;i++)ans=max(ans,f[i]);
    61     printf("%d
    ",ans);
    62 }
    CDQ打法

    树套树打法

    bzoj2244 拦截导弹

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <iostream>
      5 using namespace std;
      6 const int N=50010;
      7 int n,toth,totv,st[N],top,f[2][N];
      8 struct node
      9 {
     10     int h,v,tim;
     11     inline void read(){scanf("%d%d",&h,&v);}
     12 }m[N];
     13 inline bool mt1(const node &a,const node &b)
     14 {
     15     if(a.v==b.v&&a.h==b.h)return a.tim<b.tim;
     16     return a.h==b.h?a.v<b.v:a.h<b.h;
     17 }
     18 inline bool mt2(const node &a,const node &b)
     19     {return a.tim<b.tim;}
     20 int bit[N];
     21 double cnt[N],g[2][N],ans[N];
     22 inline int lowbit(int a){return a&-a;}
     23 inline void add(int a,int b,double c)
     24 {
     25     while(a<=totv)
     26     {
     27         if(bit[a]<b)bit[a]=b,cnt[a]=c;
     28         else if(bit[a]==b)cnt[a]+=c;
     29         a+=lowbit(a);
     30     }
     31 }
     32 inline void query(int a,int &b,double &c)
     33 {
     34     b=0,c=0.0;
     35     while(a)
     36     {
     37         if(bit[a]>b)b=bit[a],c=cnt[a];
     38         else if(bit[a]==b)c+=cnt[a];
     39         a-=lowbit(a);
     40     }
     41 }
     42 inline void clear(int a)
     43 {
     44     while(a<=totv)
     45     {
     46         if(!bit[a])return;
     47         bit[a]=0,cnt[a]=0.0,a+=lowbit(a);
     48     }
     49 }
     50 inline void CDQ(int l,int r,int o)
     51 {
     52     if(l==r)return;
     53     register int i,mi=l+r>>1;
     54     CDQ(l,mi,o);
     55     sort(m+l,m+r+1,mt1);
     56     int x=0;double u=0.0;
     57     for(i=l;i<=r;++i)
     58     {
     59         if(m[i].tim<=mi)
     60             add(m[i].v,f[o][m[i].tim],g[o][m[i].tim]);
     61         else 
     62         {
     63             query(m[i].v,x,u);
     64             if(x+1>f[o][m[i].tim])
     65                 f[o][m[i].tim]=x+1,g[o][m[i].tim]=u;
     66             else if(x+1==f[o][m[i].tim])
     67                 g[o][m[i].tim]+=u;
     68         }
     69     }
     70     for(i=l;i<=r;++i)
     71         if(m[i].tim<=mi)clear(m[i].v);
     72     sort(m+l,m+r+1,mt2);
     73     CDQ(mi+1,r,o);
     74 }
     75 inline void intn()
     76 {
     77     register int i;
     78     for(i=1;i<=n;++i)st[i]=m[i].h;
     79     sort(st+1,st+n+1),toth=unique(st+1,st+n+1)-st-1;
     80     for(i=1;i<=n;++i)
     81         m[i].h=lower_bound(st+1,st+toth+1,m[i].h)-st;
     82     for(i=1;i<=n;++i)st[i]=m[i].v;
     83     sort(st+1,st+n+1),totv=unique(st+1,st+n+1)-st-1;
     84     for(i=1;i<=n;++i)
     85         m[i].v=lower_bound(st+1,st+totv+1,m[i].v)-st;
     86 }
     87 int main()
     88 {
     89     register int i,j;scanf("%d",&n);
     90     for(i=n;i;--i)m[i].read();
     91     intn();
     92     for(i=1;i<=n;++i)
     93         m[i].tim=i,f[0][i]=f[1][i]=g[0][i]=g[1][i]=1;
     94     CDQ(1,n,0);
     95     reverse(m+1,m+n+1);
     96     for(i=1;i<=n;++i)
     97         m[i].tim=i,m[i].h=toth-m[i].h+1,m[i].v=totv-m[i].v+1;
     98     CDQ(1,n,1);
     99     int maxn=0;double sum=0;
    100     for(i=1;i<=n;++i)
    101     {
    102         if(maxn<f[0][i])maxn=f[0][i],sum=g[0][i];
    103         else if(f[0][i]==maxn)sum+=g[0][i];
    104     }
    105     printf("%d
    ",maxn);
    106     for(i=1;i<=n;++i)
    107     {
    108         if(f[0][n-i+1]+f[1][i]-1==maxn)
    109             ans[i]=g[0][n-i+1]*g[1][i]/sum;
    110         else ans[i]=0.0;
    111     }
    112     for(i=1;i<n;++i)printf("%.5lf ",ans[i]);
    113     printf("%.5lf",ans[n]);
    114 }
    BZOJ2244

    (我这两道都是拿CDQ打的2333)


    五.总结

    树套树是我们用来维护多维数据信息的有效工具,可以处理多维信息的复杂问题

    当然,在可以离线的情况下,整体二分/CDQ或许会更加优秀,我们要根据具体情况选择方法解决。

    以上。

  • 相关阅读:
    vue form dynamic validator All In one
    TypeScript api response interface All In One
    closable VS closeable All In One
    macOS 如何开启 WiFi 热点 All In One
    vue css inline style All In One
    vs2010里面 新建网站里面的 asp.net网站 和 新建项目里面的 asp.net Web应用程序 的区别 (下)
    牛腩新闻 59 整合添加新闻页 FreeTextBox 富文本编辑器,检测到有潜在危险的 Request.Form 值,DropDownList 的使用
    牛腩新闻 61尾声: error.aspx的使用 防止报错
    vs2010里面 新建网站里面的 asp.net网站 和 新建项目里面的 asp.net Web应用程序 的区别 (上)
    牛腩新闻 62:尾声续2 asp.net的编译和发布
  • 原文地址:https://www.cnblogs.com/LadyLex/p/8006478.html
Copyright © 2011-2022 走看看