• 树套树小结


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

    在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或许会更加优秀,我们要根据具体情况选择方法解决。

    以上。

  • 相关阅读:
    Django的路由系统
    Django框架简介
    域名与网站名的区别
    简单的链接样式-CSS
    用Javascript获取样式注意的地方
    null和undefined区别
    addLoadEvent(func)详解
    《Javascrip DOM 编程艺术》学习笔记-Chapter5
    某夜凌晨4点所感所悟——未来前端路
    win7-32bit-virtualbox安装问题及解决方式
  • 原文地址:https://www.cnblogs.com/LadyLex/p/8006478.html
Copyright © 2020-2023  润新知