树套树小结

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

在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

 

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

以上。

posted @ 2017-12-08 18:03 LadyLex 阅读(...) 评论(...) 编辑 收藏