码迷,mamicode.com
首页 > 其他好文 > 详细

第k小问题

时间:2019-08-25 16:05:31      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:string   ++   name   check   网络管理   uniq   rand   algorithm   网络   

例题1:[poj2104]K-th Number(区间第k小模板题)

  题意:询问给定序列静态区间第k小

  0.将区间第k小/大转化为存在k个数小于等于/大于等于它且最小/大的数(挺有用的)

  1.可持久化线段树(主席树)/可持久化字典树,这里就不写了(在线)

  2.分块,询问先二分答案,相当于求小于等于它的数个数,整块用暴力排序(初始)+二分/预处理(不用排序)来解决,散块暴力(在线)

技术图片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define K 1000
 6 #define N 100005
 7 #define bl(k) ((k-1)/K)
 8 int n,m,x,y,z,a[N],b[N],sum[N/K][N];
 9 int calc(int l,int r,int k){
10     int s=0;
11     for(int i=bl(l)+1;i<bl(r);i++)s+=sum[i][k];
12     for(int i=l;i<=min(bl(l)*K+K,r);i++)s+=(a[i]<=k);
13     if (bl(l)!=bl(r))
14         for(int i=bl(r)*K+1;i<=r;i++)s+=(a[i]<=k);
15     return s;
16 }
17 int main(){
18     scanf("%d%d",&n,&m);
19     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
20     memcpy(b,a,sizeof(a));
21     sort(b+1,b+n+1);
22     for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+n+1,a[i])-b;
23     for(int i=1;i<=n;i++)sum[bl(i)][a[i]]++;
24     for(int i=0;i<=bl(n);i++)
25         for(int j=2;j<=n;j++)sum[i][j]+=sum[i][j-1];
26     for(int i=1;i<=m;i++){
27         scanf("%d%d%d",&x,&y,&z);
28         int l=1,r=n;
29         while (l<r){
30             int mid=(l+r>>1);
31             if (calc(x,y,mid)>=z)r=mid;
32             else l=mid+1;
33         }
34         printf("%d\n",b[l]);
35     }
36 }
View Code

  3.整体二分,主要思路是将所有询问离线后,一起二分并根据答案的大小分成两部分递归下去(只能将初始序列当作修改来做)(离线)

技术图片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define N 200005
 6 #define L (k<<1)
 7 #define R (L+1)
 8 struct ji{
 9     int l,r,k,id,p;
10 }q[N],q1[N],q2[N];
11 int n,m,a[N],ans[N],f[N<<2];
12 void update(int k,int l,int r,int x,int y){
13     if (l==r){
14         f[k]+=y;
15         return;
16     }
17     int mid=(l+r>>1);
18     if (x<=mid)update(L,l,mid,x,y);
19     else update(R,mid+1,r,x,y);
20     f[k]=f[L]+f[R];
21 }
22 int query(int k,int l,int r,int x,int y){
23     if ((l>y)||(x>r))return 0;
24     if ((x<=l)&&(r<=y))return f[k];
25     int mid=(l+r>>1);
26     return query(L,l,mid,x,y)+query(R,mid+1,r,x,y);
27 }
28 void calc(int l,int r,int x,int y){
29     if (l>r)return;
30     if (x==y){
31         for(int i=l;i<=r;i++)
32             if (q[i].p)ans[q[i].id]=x;
33         return;
34     }
35     int mid=(x+y>>1),s1=0,s2=0;
36     for(int i=l;i<=r;i++)
37         if (!q[i].p)
38             if (q[i].k>mid)q2[++s2]=q[i];
39             else{
40                 update(1,1,n,q[i].id,1);
41                 q1[++s1]=q[i];
42             }
43         else{
44             int k=query(1,1,n,q[i].l,q[i].r);
45             if (k>=q[i].k)q1[++s1]=q[i];
46             else{
47                 q[i].k-=k;
48                 q2[++s2]=q[i];
49             }
50         }
51     for(int i=l;i<=r;i++)
52         if ((!q[i].p)&&(q[i].k<=mid))update(1,1,n,q[i].id,-1);
53     for(int i=1;i<=s1;i++)q[i+l-1]=q1[i];
54     for(int i=1;i<=s2;i++)q[i+l+s1-1]=q2[i];
55     calc(l,l+s1-1,x,mid);
56     calc(l+s1,r,mid+1,y);
57 }
58 int main(){
59     scanf("%d%d",&n,&m);
60     for(int i=1;i<=n;i++){
61         scanf("%d",&q[i].k);
62         q[i].id=i;
63         q[i].p=0;
64     }
65     for(int i=n+1;i<=n+m;i++){
66         scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
67         q[i].id=i-n;
68         q[i].p=1;
69     }
70     calc(1,n+m,-1e9,1e9);
71     for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
72 }
View Code

  4.一些树套树(详见例题2做法1和4~8)(在线)

 

例题2:[bzoj1901]Dynamic Rankings(动态区间第k小模板题)

  题意:询问给定序列动态(单点修改)区间第k小

  1.区间线段树套平衡树,询问二分后相当于查询一段区间内小于等于某数数个数,模板题(在线)

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 10005
 4 #define L (k<<1)
 5 #define R (L+1)
 6 #define mid (l+r>>1)
 7 #define s(p) ch[k][p]
 8 int V,n,m,p,x,y,z,a[N],ro[N<<2],sz[N*500],sum[N*500],ra[N*500],v[N*500],ch[N*500][2];
 9 char s[11];
10 void up(int k){
11     sz[k]=sz[s(0)]+sz[s(1)]+sum[k];
12 }
13 void rotate(int &k,int x,int p){
14     s(p)=ch[x][p^1];
15     ch[x][p^1]=k;
16     up(k);
17     up(k=x);
18 }
19 void add(int &k,int x){
20     if (!k){
21         v[k=++V]=x;
22         ra[k]=rand();
23         sz[k]=0; 
24     }
25     sz[k]++;
26     if (v[k]==x){
27         sum[k]++;
28         return;
29     }
30     bool p=(v[k]<x);
31     add(s(p),x);
32     if (ra[k]>ra[s(p)])rotate(k,s(p),p);
33 }
34 void del(int &k,int x){
35     sz[k]--;
36     if (v[k]==x){
37         if (--sum[k])return;
38         sum[k]++;
39         if (s(0)*s(1)==0)k=s(0)+s(1);
40         else{
41             bool p=(ra[s(0)]>ra[s(1)]);
42             rotate(k,s(p),p);
43             del(k,x);
44         }
45         return;
46     }
47     del(s(v[k]<x),x);
48 }
49 int query(int k,int x){
50     if (!k)return 0;
51     if (v[k]==x)return sum[k]+sz[s(0)];
52     bool p=(v[k]<x);
53     return query(s(p),x)+p*(sum[k]+sz[s(0)]);
54 }
55 void update(int k,int l,int r,int x,int y,int z){
56     if (y!=-1)del(ro[k],y);
57     add(ro[k],z);
58     if (l==r)return;
59     if (x<=mid)update(L,l,mid,x,y,z);
60     else update(R,mid+1,r,x,y,z);
61 }
62 int query(int k,int l,int r,int x,int y,int z){
63     if ((l>y)||(x>r))return 0;
64     if ((x<=l)&&(r<=y))return query(ro[k],z);
65     return query(L,l,mid,x,y,z)+query(R,mid+1,r,x,y,z);
66 }
67 int find(){
68     int l=0,r=1000000000;
69     while (l<r)
70         if (query(1,1,n,x,y,mid)>=z)r=mid;
71         else l=mid+1;
72     return l;
73 }
74 int main(){
75     srand(time(0));
76     scanf("%d%d",&n,&m);
77     for(int i=1;i<=n;i++){
78         scanf("%d",&a[i]);
79         update(1,1,n,i,-1,a[i]);
80     }
81     for(int i=1;i<=m;i++){
82         scanf("%s%d%d",&s,&x,&y);
83         if (s[0]==C){
84             update(1,1,n,x,a[x],y);
85             a[x]=y;
86             continue;
87         }
88         scanf("%d",&z);
89         printf("%d\n",find());
90     }
91 }
View Code

  2.分块,单点修改直接对其重新排序即可(不能预处理了),其他同例题1做法2(在线)

技术图片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define K 100
 6 #define N 10005
 7 #define bl(k) ((k-1)/K)
 8 int n,m,x,y,z,a[N],aa[K][N];
 9 char s[11];
10 int calc(int l,int r,int k){
11     int s=0;
12     for(int i=bl(l)+1;i<bl(r);i++)
13         s+=upper_bound(aa[i]+1,aa[i]+aa[i][0]+1,k)-aa[i]-1;
14     for(int i=l;i<=min(bl(l)*K+K,r);i++)s+=(a[i]<=k);
15     if (bl(l)!=bl(r))
16         for(int i=bl(r)*K+1;i<=r;i++)s+=(a[i]<=k);
17     return s;
18 }
19 int main(){
20     scanf("%d%d",&n,&m);
21     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
22     for(int i=1;i<=n;i++)aa[bl(i)][++aa[bl(i)][0]]=a[i];
23     for(int i=0;i<=bl(n);i++)sort(aa[i]+1,aa[i]+aa[i][0]+1); 
24     for(int i=1;i<=m;i++){
25         scanf("%s%d%d",s,&x,&y);
26         if (s[0]==C){
27             for(int j=1;j<=aa[bl(x)][0];j++)
28                 if (aa[bl(x)][j]==a[x]){
29                     a[x]=aa[bl(x)][j]=y;
30                     break;
31                 }
32             sort(aa[bl(x)]+1,aa[bl(x)]+aa[bl(x)][0]+1);
33             continue;
34         }
35         scanf("%d",&z);
36         int l=-1e9,r=1e9;
37         while (l<r){
38             int mid=(l+r>>1);
39             if (calc(x,y,mid)>=z)r=mid;
40             else l=mid+1;
41         }
42         printf("%d\n",l);
43     }
44 }
View Code

  3.整体二分,将修改改为删除和加入两个操作,其他同例题1做法3(离线)

技术图片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define N 30005
 6 #define L (k<<1)
 7 #define R (L+1)
 8 struct ji{
 9     int l,r,k,id,p;
10 }q[N],q1[N],q2[N];
11 int n,m,a[N],ans[N],f[N<<2];
12 char s[11];
13 void update(int k,int l,int r,int x,int y){
14     if (l==r){
15         f[k]+=y;
16         return;
17     }
18     int mid=(l+r>>1);
19     if (x<=mid)update(L,l,mid,x,y);
20     else update(R,mid+1,r,x,y);
21     f[k]=f[L]+f[R];
22 }
23 int query(int k,int l,int r,int x,int y){
24     if ((l>y)||(x>r))return 0;
25     if ((x<=l)&&(r<=y))return f[k];
26     int mid=(l+r>>1);
27     return query(L,l,mid,x,y)+query(R,mid+1,r,x,y);
28 }
29 void calc(int l,int r,int x,int y){//处理[l,r]内的所有操作(保证答案在[x,y]区间中)
30     if (l>r)return;
31     if (x==y){
32         for(int i=l;i<=r;i++)
33             if (q[i].p==1)ans[q[i].id]=x;
34         return;
35     }
36     int mid=(x+y>>1),s1=0,s2=0;
37     for(int i=l;i<=r;i++)
38         if (!q[i].p)
39             if (q[i].k>mid)q2[++s2]=q[i];
40             else{
41                 update(1,1,n,q[i].id,1);
42                 q1[++s1]=q[i];
43             }
44         else
45             if (q[i].p==2)
46                 if (q[i].k>mid)q2[++s2]=q[i];
47                 else{
48                     update(1,1,n,q[i].id,-1);
49                     q1[++s1]=q[i];
50                 }
51             else{
52                 int k=query(1,1,n,q[i].l,q[i].r);
53                 if (k>=q[i].k)q1[++s1]=q[i];
54                 else{
55                     q[i].k-=k;
56                     q2[++s2]=q[i];
57                 }
58             }
59     for(int i=l;i<=r;i++)
60         if (q[i].k<=mid){
61             if (!q[i].p)update(1,1,n,q[i].id,-1);
62             if (q[i].p==2)update(1,1,n,q[i].id,1);
63         }
64     for(int i=1;i<=s1;i++)q[i+l-1]=q1[i];
65     for(int i=1;i<=s2;i++)q[i+l+s1-1]=q2[i];
66     calc(l,l+s1-1,x,mid);
67     calc(l+s1,r,mid+1,y);
68 }
69 int main(){
70     scanf("%d%d",&n,&m);
71     for(int i=1;i<=n;i++){
72         scanf("%d",&a[i]);
73         q[i]=ji{0,0,a[i],i,0};
74     }
75     int x,y,z,tot=n,qq=0;
76     for(int i=1;i<=m;i++){
77         scanf("%s%d%d",s,&x,&y);
78         if (s[0]==C){
79             q[++tot]={0,0,a[x],x,2};
80             q[++tot]={0,0,a[x]=y,x,0};
81             continue;
82         }
83         scanf("%d",&z);
84         q[++tot]={x,y,z,++qq,1};
85     }
86     calc(1,tot,-1e9,1e9);
87     for(int i=1;i<=qq;i++)printf("%d\n",ans[i]);
88 }
View Code

  4.区间线段树套权值线段树,将对应区间划分为log个区间,相当于在log棵权值线段树上查询第k大,类似于主席树(在线)

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 10005
 4 #define L (k<<1)
 5 #define R (L+1)
 6 #define mid (l+r>>1)
 7 int V,n,m,x,y,z,a[N],b[N],ro[N<<2],f[N*900],ch[N*900][2];
 8 char s[11];
 9 void update(int &k,int l,int r,int x,int y){
10     if (!k)k=++V; 
11     if (l==r){
12         f[k]+=y;
13         return;
14     }
15     if (x<=mid)update(ch[k][0],l,mid,x,y);
16     else update(ch[k][1],mid+1,r,x,y);
17     f[k]=f[ch[k][0]]+f[ch[k][1]];
18 }
19 int query(int l,int r,int x){
20     if (l==r)return l;
21     int s=0;
22     for(int i=1;i<=b[0];i++)s+=f[ch[b[i]][0]];
23     for(int i=1;i<=b[0];i++)b[i]=ch[b[i]][s<x];
24     if (s>=x)return query(l,mid,x);
25     return query(mid+1,r,x-s);
26 }
27 void update(int k,int l,int r,int x,int y,int z){
28     update(ro[k],-1e9,1e9,y,z);
29     if (l==r)return;
30     if (x<=mid)update(L,l,mid,x,y,z);
31     else update(R,mid+1,r,x,y,z);
32 }
33 void query(int k,int l,int r,int x,int y){
34     if ((l>y)||(x>r))return;
35     if ((x<=l)&&(r<=y)){
36         b[++b[0]]=ro[k];
37         return;
38     }
39     query(L,l,mid,x,y);
40     query(R,mid+1,r,x,y);
41 }
42 int main(){
43     scanf("%d%d",&n,&m);
44     for(int i=1;i<=n;i++){
45         scanf("%d",&a[i]);
46         update(1,1,n,i,a[i],1);
47     }
48     for(int i=1;i<=m;i++){
49         scanf("%s%d%d",s,&x,&y);
50         if (s[0]==C){
51             update(1,1,n,x,a[x],-1);
52             update(1,1,n,x,a[x]=y,1);
53             continue;
54         }
55         scanf("%d",&z);
56         b[0]=0;
57         query(1,1,n,x,y);
58         printf("%d\n",query(-1e9,1e9,z));
59     }
60 }
View Code

  5.权值线段树套平衡树,平衡树表示对应权值区间的下标,查询直接在权值线段树上二分(类似于例题2做法1反过来统计)(在线)

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 10005
 4 #define mid (l+r>>1)
 5 #define s(p) ch[k][p]
 6 int V1,V2,n,m,r,p,x,y,z,a[N],ro[N*60],ls[N*60],rs[N*60],sz[N*500],sum[N*500],ra[N*500],v[N*500],ch[N*500][2];
 7 char s[11];
 8 void up(int k){
 9     sz[k]=sz[s(0)]+sz[s(1)]+sum[k];
10 }
11 void rotate(int &k,int x,int p){
12     s(p)=ch[x][p^1];
13     ch[x][p^1]=k;
14     up(k);
15     up(k=x);
16 }
17 void add(int &k,int x){
18     if (!k){
19         v[k=++V2]=x;
20         ra[k]=rand();
21         sz[k]=0; 
22     }
23     sz[k]++;
24     if (v[k]==x){
25         sum[k]++;
26         return;
27     }
28     bool p=(v[k]<x);
29     add(s(p),x);
30     if (ra[k]>ra[s(p)])rotate(k,s(p),p);
31 }
32 void del(int &k,int x){
33     sz[k]--;
34     if (v[k]==x){
35         if (--sum[k])return;
36         sum[k]++;
37         if (s(0)*s(1)==0)k=s(0)+s(1);
38         else{
39             bool p=(ra[s(0)]>ra[s(1)]);
40             rotate(k,s(p),p);
41             del(k,x);
42         }
43         return;
44     }
45     del(s(v[k]<x),x);
46 }
47 int query(int k,int x){
48     if (!k)return 0;
49     if (v[k]==x)return sum[k]+sz[s(0)];
50     bool p=(v[k]<x);
51     return query(s(p),x)+p*(sum[k]+sz[s(0)]);
52 }
53 void update(int &k,int l,int r,int x,int y,int z){
54     if (!k)k=++V1;
55     if (z==1)add(ro[k],y);
56     else del(ro[k],y);
57     if (l==r)return;
58     if (x<=mid)update(ls[k],l,mid,x,y,z);
59     else update(rs[k],mid+1,r,x,y,z);
60 }
61 int query(int k,int l,int r,int x,int y,int a,int b){
62     if ((!k)||(l>y)||(x>r))return 0;
63     if ((x<=l)&&(r<=y))return query(ro[k],b)-query(ro[k],a-1);
64     return query(ls[k],l,mid,x,y,a,b)+query(rs[k],mid+1,r,x,y,a,b);
65 }
66 int find(){
67     int l=-1e9,r=1e9;
68     while (l<r)
69         if (query(1,-1e9,1e9,-1e9,mid,x,y)>=z)r=mid;
70         else l=mid+1;
71     return l;
72 }
73 int main(){
74     srand(time(0));
75     scanf("%d%d",&n,&m);
76     for(int i=1;i<=n;i++){
77         scanf("%d",&a[i]);
78         update(r,-1e9,1e9,a[i],i,1);
79     }
80     for(int i=1;i<=m;i++){
81         scanf("%s%d%d",&s,&x,&y);
82         if (s[0]==C){
83             update(r,-1e9,1e9,a[x],x,-1);
84             update(r,-1e9,1e9,a[x]=y,x,1);
85             continue;
86         }
87         scanf("%d",&z);
88         printf("%d\n",find());
89     }
90 }
View Code

  6.权值线段树套权值线段树,类似于例题2做法5,只是将下标放在权值线段树中统计(在线)

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 10005
 4 #define mid (l+r>>1)
 5 int V,n,m,r,x,y,z,a[N],f[N*500],ls[N*500],rs[N*500];
 6 char s[11];
 7 void update(int &k,int l,int r,int x,int y){
 8     if (!k)k=++V;
 9     if (l==r){
10         f[k]+=y;
11         return;
12     }
13     if (x<=mid)update(ls[k],l,mid,x,y);
14     else update(rs[k],mid+1,r,x,y);
15     f[k]=f[ls[k]]+f[rs[k]];
16 }
17 int query(int k,int l,int r,int x,int y){
18     if ((!k)||(l>y)||(x>r))return 0;
19     if ((x<=l)&&(r<=y))return f[k];
20     return query(ls[k],l,mid,x,y)+query(rs[k],mid+1,r,x,y);
21 }
22 void update(int &k,int l,int r,int x,int y,int z){
23     if (!k)k=++V;
24     update(f[k],1,n,y,z);
25     if (l==r)return;
26     if (x<=mid)update(ls[k],l,mid,x,y,z);
27     else update(rs[k],mid+1,r,x,y,z);
28 }
29 int query(int k,int l,int r,int x,int y,int a,int b){
30     if ((!k)||(l>y)||(x>r))return 0;
31     if ((x<=l)&&(r<=y))return query(f[k],1,n,1,b)-query(f[k],1,n,1,a-1);
32     return query(ls[k],l,mid,x,y,a,b)+query(rs[k],mid+1,r,x,y,a,b);
33 }
34 int find(){
35     int l=-1e9,r=1e9;
36     while (l<r)
37         if (query(1,-1e9,1e9,-1e9,mid,x,y)>=z)r=mid;
38         else l=mid+1;
39     return l;
40 }
41 int main(){
42     scanf("%d%d",&n,&m);
43     for(int i=1;i<=n;i++){
44         scanf("%d",&a[i]);
45         update(r,-1e9,1e9,a[i],i,1);
46     }
47     for(int i=1;i<=m;i++){
48         scanf("%s%d%d",&s,&x,&y);
49         if (s[0]==C){
50             update(r,-1e9,1e9,a[x],x,-1);
51             update(r,-1e9,1e9,a[x]=y,x,1);
52             continue;
53         }
54         scanf("%d",&z);
55         printf("%d\n",find());
56     }
57 }
View Code

  7.平衡树(非旋)套平衡树,外层平衡树维护位置,平衡树每一个节点再开一棵平衡树表示子数内所有节点权值,询问二分(在线)

技术图片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 5000005
  4 #define s(p) ch[k][p]
  5 #define mid (l+r>>1)
  6 int V,r,n,m,p,x,y,z,v[10005],a[N],ro[N],tot[N],sz[N],ch[N][2];
  7 char s[11];
  8 void New(int k,int x){
  9     a[k]=x;
 10     ro[k]=rand();
 11 }
 12 void up(int k){
 13     sz[k]=sz[s(0)]+sz[s(1)]+tot[k];
 14 }
 15 void rotate(int &k,int u,int p){
 16     s(p)=ch[u][p^1];
 17     ch[u][p^1]=k;
 18     up(k);
 19     up(k=u);
 20 }
 21 void add(int &k,int x){
 22     if (!k)New(k=++V,x);
 23     sz[k]++;
 24     if (a[k]==x){
 25         tot[k]++;
 26         return;
 27     }
 28     bool p=(a[k]<x);
 29     add(s(p),x);
 30     if (ro[s(p)]<ro[k])rotate(k,s(p),p);
 31 }
 32 void del(int &k,int x){
 33     if (!k)return;
 34     sz[k]--;
 35     if (a[k]==x){
 36         if (--tot[k])return;
 37         tot[k]++;
 38         if (s(0)*s(1)==0)k=s(0)+s(1);
 39         else{
 40             int p=(ro[s(0)]>ro[s(1)]);
 41             rotate(k,s(p),p);
 42             del(k,x);
 43         }
 44         return;
 45     }
 46     del(s(a[k]<x),x);
 47 }
 48 int query(int k,int x){
 49     if (!k)return 0;
 50     return query(s(a[k]<=x),x)+(a[k]<=x)*(sz[s(0)]+tot[k]);
 51 }
 52 bool check(int k){
 53     return max(sz[s(0)],sz[s(1)])*10>sz[k]*7;
 54 }
 55 int update(int k,int x,int y){
 56     add(ro[k],y);
 57     if (x==sz[s(0)]){
 58         swap(a[k],y);
 59         del(ro[k],y);
 60         return y;
 61     }
 62     bool p=(sz[s(0)]<x);
 63     y=update(s(p),x-p*(sz[s(0)]+1),y);
 64     del(ro[k],y);
 65     return y;
 66 }
 67 int find(int k,int x,int y,int z){
 68     if ((x==1)&&(y==sz[k]))return query(ro[k],z);
 69     int s=0;
 70     if (x<=sz[s(0)])s+=find(s(0),x,min(y,sz[s(0)]),z);
 71     x-=sz[s(0)]+1;
 72     y-=sz[s(0)]+1;
 73     if (0<y)s+=find(s(1),max(x,1),y,z);
 74     if ((x<=0)&&(0<=y))s+=(a[k]<=z);
 75     return s;
 76 }
 77 void build(int &k,int l,int r){
 78     if (l>r){
 79         k=0;
 80         return;
 81     }
 82     k=mid;
 83     build(s(0),l,mid-1);
 84     build(s(1),mid+1,r);
 85     sz[k]=sz[s(0)]+sz[s(1)]+1;
 86     ro[k]=0;
 87     for(int i=l;i<=r;i++)add(ro[k],a[i]);
 88 }
 89 int find(){
 90     int l=-1e9,r=1e9;
 91     while (l<r)
 92         if (find((n+1)/2,x,y,mid)>=z)r=mid;
 93         else l=mid+1;
 94     return l;
 95 }
 96 int main(){
 97     scanf("%d%d",&n,&m);
 98     V=n;
 99     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
100     build(r,1,n);
101     for(int i=1;i<=m;i++){
102         scanf("%s%d%d",s,&x,&y);
103         if (s[0]==C)update(r,x-1,y);
104         if (s[0]==Q){
105             scanf("%d",&z);
106             printf("%d\n",find());
107         }
108     }
109 }
View Code

  8.平衡树(非选)套权值线段树,类似于例题2做法7,只是用权值线段树来维护,但可以直接在权值线段树上二分(在线)

技术图片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 10005
  4 #define s(p) ch[k][p]
  5 #define mid (l+r>>1)
  6 int V,r,n,m,p,x,y,z,ans,ro[N],a[N],v[N],v2[N],sz[N*1000],ch[N*1000][2];
  7 char s[11];
  8 void update(int &k,int l,int r,int x,int y){
  9     if (!k)k=++V;
 10     sz[k]+=y;
 11     if (l==r)return;
 12     if (x<=mid)update(s(0),l,mid,x,y);
 13     else update(s(1),mid+1,r,x,y);
 14 }
 15 int query(int l,int r,int x){
 16     if (l==r)return l;
 17     int s=0;
 18     for(int i=1;i<=v[0];i++)s+=sz[ch[v[i]][0]];
 19     for(int i=1;i<=v2[0];i++)s+=(((l<=v2[i])&&(v2[i]<=mid)));
 20     for(int i=1;i<=v[0];i++)v[i]=ch[v[i]][(s<x)];
 21     if (s>=x)query(l,mid,x);
 22     else query(mid+1,r,x-s);
 23 }
 24 void merge(int &k,int k1,int k2){
 25     if (k1+k2==0)return;
 26     sz[k=++V]=sz[k1]+sz[k2];
 27     merge(s(0),ch[k1][0],ch[k2][0]);
 28     merge(s(1),ch[k1][1],ch[k2][1]);
 29 }
 30 bool check(int k){
 31     return max(sz[s(0)],sz[s(1)])*10>sz[k]*7;
 32 }
 33 void up(int k){
 34     sz[k]=sz[s(0)]+sz[s(1)]+1;
 35     merge(ro[k],ro[s(0)],ro[s(1)]);
 36     update(ro[k],-1e9,1e9,a[k],1);
 37 }
 38 int update(int k,int x,int y){
 39     update(ro[k],-1e9,1e9,y,1);
 40     if (x==sz[s(0)]){
 41         swap(a[k],y);
 42         update(ro[k],-1e9,1e9,y,-1);
 43         return y;
 44     }
 45     bool p=(sz[s(0)]<x);
 46     y=update(s(p),x-p*(sz[s(0)]+1),y);
 47     update(ro[k],-1e9,1e9,y,-1);
 48     return y;
 49 }
 50 void find(int k,int x,int y){
 51     if ((x==1)&&(y==sz[k])){
 52         v[++v[0]]=ro[k];
 53         return;
 54     }
 55     if (x<=sz[s(0)])find(s(0),x,min(y,sz[s(0)]));
 56     x-=sz[s(0)]+1;
 57     y-=sz[s(0)]+1;
 58     if (0<y)find(s(1),max(x,1),y);
 59     if ((x<=0)&&(0<=y))v2[++v2[0]]=a[k];
 60 }
 61 void dfs(int k){
 62     if (!k)return;
 63     dfs(s(0));
 64     v[++v[0]]=k;
 65     dfs(s(1));
 66 }
 67 void build(int &k,int l,int r){
 68     if (l>r){
 69         k=0;
 70         return;
 71     }
 72     k=v[mid];
 73     build(s(0),l,mid-1);
 74     build(s(1),mid+1,r);
 75     up(k);
 76 }
 77 void find(int &k,int x){
 78     if (check(k)){
 79         v[0]=0;
 80         dfs(k);
 81         build(k,1,v[0]);
 82         return;
 83     }
 84     if (x==sz[s(0)])return;
 85     bool p=(sz[s(0)]<x);
 86     find(s(p),x-p*(sz[s(0)]+1));
 87 }
 88 int main(){
 89     scanf("%d%d",&n,&m);
 90     V=n;
 91     for(int i=1;i<=n;i++){
 92         scanf("%d",&a[i]);
 93         v[i]=i;
 94     }
 95     build(r,1,n);
 96     for(int i=1;i<=m;i++){
 97         scanf("%s%d%d",s,&x,&y);
 98         if (s[0]==C)update(r,x-1,y);
 99         if (s[0]==Q){
100             scanf("%d",&z);
101             v[0]=v2[0]=0;
102             find(r,x,y);
103             printf("%d\n",ans=query(-1e9,1e9,z));
104         }
105     }
106 }
View Code

 

例题3:[bzoj3065]带插入区间K小值(动态带插入区间第k小模板题,强制在线)

  题意:询问给定序列动态(单点修改和单点插入)区间第k小

  1.平衡树(非旋)套权值线段树,同例题2做法8(在线)

技术图片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 70005
  4 #define s(p) ch[k][p]
  5 #define mid (l+r>>1)
  6 int r,n,m,p,x,y,z,ans,ro[N],a[N],v[N],v2[N],st[N*300],sz[N*300],ch[N*300][2];
  7 char s[11];
  8 void update(int &k,int l,int r,int x,int y){
  9     if (!k)k=st[st[0]--];
 10     sz[k]+=y;
 11     if (l==r)return;
 12     if (x<=mid)update(s(0),l,mid,x,y);
 13     else update(s(1),mid+1,r,x,y);
 14     if (!sz[k]){
 15         st[++st[0]]=k;
 16         s(0)=s(1)=k=0;
 17     }
 18 }
 19 int query(int l,int r,int x){
 20     if (l==r)return l;
 21     int s=0;
 22     for(int i=1;i<=v[0];i++)s+=sz[ch[v[i]][0]];
 23     for(int i=1;i<=v2[0];i++)s+=(((l<=v2[i])&&(v2[i]<=mid)));
 24     for(int i=1;i<=v[0];i++)v[i]=ch[v[i]][(s<x)];
 25     if (s>=x)query(l,mid,x);
 26     else query(mid+1,r,x-s);
 27 }
 28 void merge(int &k,int k1,int k2){
 29     if (k1+k2==0)return;
 30     sz[k=st[st[0]--]]=sz[k1]+sz[k2];
 31     merge(s(0),ch[k1][0],ch[k2][0]);
 32     merge(s(1),ch[k1][1],ch[k2][1]);
 33 }
 34 bool check(int k){
 35     return max(sz[s(0)],sz[s(1)])*4>sz[k]*3;
 36 }
 37 void up(int k){
 38     sz[k]=sz[s(0)]+sz[s(1)]+1;
 39     merge(ro[k],ro[s(0)],ro[s(1)]);
 40     update(ro[k],0,N,a[k],1);
 41 }
 42 void add(int &k,int x,int y){
 43     if (!k){
 44         sz[k=++n]=1;
 45         update(ro[k],0,N,a[k]=y,1);
 46         return;
 47     }
 48     sz[k]++;
 49     update(ro[k],0,N,y,1);
 50     bool p=(sz[s(0)]<x);
 51     add(s(p),x-p*(sz[s(0)]+1),y);
 52 }
 53 int update(int k,int x,int y){
 54     update(ro[k],0,N,y,1);
 55     if (x==sz[s(0)]){
 56         swap(a[k],y);
 57         update(ro[k],0,N,y,-1);
 58         return y;
 59     }
 60     bool p=(sz[s(0)]<x);
 61     y=update(s(p),x-p*(sz[s(0)]+1),y);
 62     update(ro[k],0,N,y,-1);
 63     return y;
 64 }
 65 void find(int k,int x,int y){
 66     if ((x==1)&&(y==sz[k])){
 67         v[++v[0]]=ro[k];
 68         return;
 69     }
 70     if (x<=sz[s(0)])find(s(0),x,min(y,sz[s(0)]));
 71     x-=sz[s(0)]+1;
 72     y-=sz[s(0)]+1;
 73     if (0<y)find(s(1),max(x,1),y);
 74     if ((x<=0)&&(0<=y))v2[++v2[0]]=a[k];
 75 }
 76 void dfs(int k){
 77     if (!k)return;
 78     dfs(s(0));
 79     v[++v[0]]=k;
 80     dfs(s(1));
 81 }
 82 void build(int &k,int l,int r){
 83     if (l>r){
 84         k=0;
 85         return;
 86     }
 87     k=v[mid];
 88     build(s(0),l,mid-1);
 89     build(s(1),mid+1,r);
 90     up(k);
 91 }
 92 void find(int &k,int x){
 93     if (check(k)){
 94         v[0]=0;
 95         dfs(k);
 96         build(k,1,v[0]);
 97         return;
 98     }
 99     if (x==sz[s(0)])return;
100     bool p=(sz[s(0)]<x);
101     find(s(p),x-p*(sz[s(0)]+1));
102 }
103 int main(){
104     scanf("%d",&n);
105     for(int i=N;i<=300*(N-5);i++)st[++st[0]]=i;
106     for(int i=1;i<=n;i++){
107         scanf("%d",&a[i]);
108         v[i]=i;
109     }
110     build(r,1,n);
111     scanf("%d",&m);
112     for(int i=1;i<=m;i++){
113         scanf("%s%d%d",s,&x,&y);
114         x^=ans;
115         y^=ans;
116         if (s[0]==M)update(r,x-1,y);
117         if (s[0]==I){
118             add(r,x-1,y);
119             find(r,x-1);
120         }
121         if (s[0]==Q){
122             scanf("%d",&z);
123             v[0]=v2[0]=0;
124             find(r,x,y);
125             printf("%d\n",ans=query(0,N,z^ans));
126         }
127     }
128 }
View Code

  2.分块,插入操作暴力在块内插入,当发现块大小大于等于两倍标准块大小就暴力重构即可,其他同例题2做法2(在线)

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 70005
 4 #define K 400
 5 int S,n,m,x,y,z,ans,t,nex[N],sz[N],a[N/K+10][2*K+10],b[N/K+10][2*K+10];
 6 char s[11];
 7 void px(int k){
 8     memcpy(b[k],a[k],sizeof(a[k]));
 9     sort(b[k]+1,b[k]+sz[k]+1);
10 }
11 void split(int k){
12     sz[k]=sz[++S]=K;
13     for(int i=1;i<=K;i++)swap(a[S][i],a[k][i+K]);
14     nex[S]=nex[k];
15     px(nex[k]=S);
16 }
17 int calc(int k){
18     int ans=0;
19     t=sz[0];
20     for(int i=0;i!=-1;t+=sz[i=nex[i]]){
21         if (x<=t){
22             if (y<=t){
23                 for(int j=x;j<=y;j++)ans+=(a[i][j-t+sz[i]]<=k);
24                 return ans;
25             }
26             for(int j=x;j<=t;j++)ans+=(a[i][j-t+sz[i]]<=k);
27             for(int j=nex[i],t2=t+sz[j];j!=-1;t2+=sz[j=nex[j]])
28                 if (t2<y)ans+=upper_bound(b[j]+1,b[j]+sz[j]+1,k)-b[j]-1;
29                 else{
30                     for(int l=t2-sz[j]+1;l<=y;l++)ans+=(a[j][l-t2+sz[j]]<=k);
31                     return ans;
32                 }
33         }
34     }
35 }
36 int find(){
37     int l=0,r=70000;
38     while (l<r){
39         int mid=(l+r>>1);
40         if (calc(mid)>=z)r=mid;
41         else l=mid+1;
42     }
43     return l;
44 }
45 int main(){
46     scanf("%d",&n);
47     S=n/K;
48     for(int i=1;i<=n;i++)scanf("%d",&a[i/K][++sz[i/K]]);
49     for(int i=0;i<S;i++)nex[i]=i+1;
50     nex[S]=-1;
51     for(int i=0;i<=S;i++)px(i);
52     scanf("%d",&m);
53     for(int i=1;i<=m;i++){
54         scanf("%s%d%d",s,&x,&y);
55         x^=ans;
56         y^=ans;
57         t=sz[0];
58         if (s[0]==M)
59             for(int j=0;j!=-1;t+=sz[j=nex[j]])
60                 if (x<=t){
61                     a[j][sz[j]-t+x]=y;
62                     px(j);
63                     break;
64                 }
65         if (s[0]==I)
66             for(int j=0;j!=-1;t+=sz[j=nex[j]])
67                 if (x-1<=t){
68                     for(int k=0;k<=t-x;k++)swap(a[j][sz[j]-k],a[j][sz[j]-k+1]);
69                     a[j][sz[j]-t+x]=y;
70                     if (++sz[j]==2*K)split(j);
71                     px(j);
72                     break;
73                 }
74         if (s[0]==Q){
75             scanf("%d",&z);
76             z^=ans;
77             printf("%d\n",ans=find());
78         }
79     }
80 }
View Code

 

例题4:[bzoj3110]K大数查询(区间加入+区间第k小模板题

  题意:询问给定序列动态(区间加入,不删除)区间第k小

  1.权值线段树套权值线段树,同例2做法6

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 50005
 4 #define mid (l+r>>1)
 5 #define ll long long
 6 int V,n,m,r,p,x,y,z,ls[N*400],rs[N*400],f[N*400];
 7 ll sum[N*400];
 8 char s[11];
 9 void update(int &k,int l,int r,int x,int y){
10     if (!k)k=++V;
11     if ((l>y)||(x>r))return;
12     sum[k]+=min(r,y)-max(l,x)+1; 
13     if ((x<=l)&&(r<=y)){
14         f[k]++;
15         return;
16     }
17     update(ls[k],l,mid,x,y);
18     update(rs[k],mid+1,r,x,y);
19 }
20 ll query(int k,int l,int r,int x,int y){
21     if ((!k)||(l>y)||(x>r))return 0;
22     if ((x<=l)&&(r<=y))return sum[k];
23     return f[k]*(min(r,y)-max(l,x)+1LL)+query(ls[k],l,mid,x,y)+query(rs[k],mid+1,r,x,y);
24 }
25 void update(int &k,int l,int r,int x,int y,int z){ 
26     if (!k)k=++V;
27     update(f[k],1,n,y,z);
28     if (l==r)return;
29     if (x<=mid)update(ls[k],l,mid,x,y,z);
30     else update(rs[k],mid+1,r,x,y,z);
31 }
32 int query(int k,int l,int r,int x,int y,int z){
33     if (l==r)return l;
34     ll t=query(f[ls[k]],1,n,x,y);
35     if (z<=t)query(ls[k],l,mid,x,y,z);
36     else query(rs[k],mid+1,r,x,y,z-t);
37 }
38 int main(){
39     scanf("%d%d",&n,&m);
40     for(int i=1;i<=m;i++){
41         scanf("%d%d%d%d",&p,&x,&y,&z);
42         if (p==1)update(r,-n,n,-z,x,y);
43         else printf("%d\n",-query(r,-n,n,x,y,z));
44     }
45 }
View Code

  2.整体二分,同例题2做法3,只是变为区间修改和区间查询,只能用线段树(离线)

技术图片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define N 50005
 6 #define L (k<<1)
 7 #define R (L+1)
 8 #define ll long long
 9 struct ji{
10     int l,r,k,id,p;
11 }q[N],q1[N],q2[N];
12 int n,m,a[N],ans[N],laz[N<<3];
13 ll f[N<<3];
14 char s[11];
15 void update(int k,int l,int r,int x,int y,int z){
16     if ((l>y)||(x>r))return;
17     f[k]+=(min(r,y)-max(l,x)+1)*z;
18     if ((x<=l)&&(r<=y)){
19         laz[k]+=z;
20         return;
21     }
22     int mid=(l+r>>1);
23     update(L,l,mid,x,y,z);
24     update(R,mid+1,r,x,y,z);
25 }
26 ll query(int k,int l,int r,int x,int y){
27     if ((l>y)||(x>r))return 0;
28     if ((x<=l)&&(r<=y))return f[k];
29     int mid=(l+r>>1);
30     return laz[k]*(min(r,y)-max(l,x)+1LL)+query(L,l,mid,x,y)+query(R,mid+1,r,x,y);
31 }
32 void calc(int l,int r,int x,int y){
33     if (l>r)return;
34     if (x==y){
35         for(int i=l;i<=r;i++)
36             if (q[i].p)ans[q[i].id]=-x;
37         return;
38     }
39     int mid=(x+y>>1),s1=0,s2=0;
40     for(int i=l;i<=r;i++)
41         if (!q[i].p)
42             if (q[i].k>mid)q2[++s2]=q[i];
43             else{
44                 update(1,1,n,q[i].l,q[i].r,1);
45                 q1[++s1]=q[i];
46             }
47         else{
48             ll k=query(1,1,n,q[i].l,q[i].r);
49             if (k>=q[i].k)q1[++s1]=q[i];
50             else{
51                 q[i].k-=k;
52                 q2[++s2]=q[i];
53             }
54         }
55     for(int i=l;i<=r;i++)
56         if ((q[i].k<=mid)&&(!q[i].p))update(1,1,n,q[i].l,q[i].r,-1);
57     for(int i=1;i<=s1;i++)q[i+l-1]=q1[i];
58     for(int i=1;i<=s2;i++)q[i+l+s1-1]=q2[i];
59     calc(l,l+s1-1,x,mid);
60     calc(l+s1,r,mid+1,y);
61 }
62 int main(){
63     scanf("%d%d",&n,&m);
64     int p,x,y,z,tot=0,qq=0;
65     for(int i=1;i<=m;i++){
66         scanf("%d%d%d%d",&p,&x,&y,&z);
67         if (p==1)q[++tot]={x,y,-z,0,0};
68         else q[++tot]={x,y,z,++qq,1};
69     }
70     calc(1,tot,-n,n);
71     for(int i=1;i<=qq;i++)printf("%d\n",ans[i]);
72 }
View Code

 

例题5:[bzoj2588]Count on a tree(树上第k小模板题,强制在线)

  题意:询问给定树静态数链第k小

  1.可持久化线段树(主席树),每一个点以父亲为基础建立可持久化线段树,做差分即可(在线)

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mid (l+r>>1)
 4 #define N 200001
 5 struct ji{
 6     int nex,to;
 7 }edge[N<<1];
 8 int E,V,n,m,t,x,y,z,ans,a[N],f[21][N],head[N],sz[20*N],b[N],son[2][20*N],s[N],r[N];
 9 char s1[11];
10 void add(int x,int y){
11     edge[E].nex=head[x];
12     edge[E].to=y;
13     head[x]=E++;
14 }
15 int ne(int &k){
16     if (!k)k=++V;
17     return k;
18 }
19 int lca(int x,int y){
20     if (s[x]<s[y])swap(x,y);
21     for(int i=20;i>=0;i--)
22         if (s[f[i][x]]>=s[y])x=f[i][x];
23     if (x==y)return x;
24     for(int i=20;i>=0;i--)
25         if (f[i][x]!=f[i][y]){
26             x=f[i][x];
27             y=f[i][y];
28         }
29     return f[0][x];
30 }
31 void update(int k1,int k2,int l,int r,int x){
32     sz[k1]=sz[k2]+1;
33     if (l==r)return;
34     int p=(x>mid);
35     son[p^1][k1]=son[p^1][k2];
36     update(ne(son[p][k1]),son[p][k2],l+(mid-l+1)*p,mid+(r-mid)*p,x);
37 }
38 int query(int l,int r,int x,int a,int b,int c,int d){
39     if (l==r)return l;
40     int t=sz[son[0][a]]+sz[son[0][b]]-sz[son[0][c]]-sz[son[0][d]],p=(x>t);
41     return query(l+(mid-l+1)*p,mid+(r-mid)*p,x-p*t,son[p][a],son[p][b],son[p][c],son[p][d]);
42 }
43 void dfs(int k,int fa){
44     s[k]=s[f[0][k]=fa]+1;
45     for(int i=1;i<=20;i++)f[i][k]=f[i-1][f[i-1][k]];
46     update(ne(r[k]),r[fa],1,m,a[k]);
47     for(int i=head[k];i!=-1;i=edge[i].nex)
48         if (edge[i].to!=fa)dfs(edge[i].to,k);
49 }
50 int main(){
51     scanf("%d%d",&n,&t);
52     memset(head,-1,sizeof(head));
53     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
54     memcpy(b,a,sizeof(b));
55     sort(b+1,b+n+1);
56     m=unique(b+1,b+n+1)-b-1;
57     for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+m+1,a[i])-b;
58     for(int i=1;i<n;i++){
59         scanf("%d%d",&x,&y);
60         add(x,y);
61         add(y,x);
62     }
63     dfs(1,0);
64     for(int i=1;i<=20;i++)
65         for(int j=1;j<=n;j++)f[i][j]=f[i-1][f[i-1][j]];
66     while (t--){
67         scanf("%d%d%d",&x,&y,&z);
68         x^=ans;
69         printf("%d\n",ans=b[query(1,m,z,r[x],r[y],r[lca(x,y)],r[f[0][lca(x,y)]])]);
70     }
71 }
View Code

  2.树链剖分后同例题1(除整体二分)(在线)(代码只有做法1)

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define mid (l+r>>1)
 5 struct ji{
 6     int nex,to;
 7 }edge[N<<1];
 8 int E,n,m,x,y,z,ans,a[N],b[N],head[N],fa[N],sh[N],sz[N],ma[N],top[N],id[N];
 9 int V,t,r[N],zh[N],fu[N],f[N*20],ls[N*20],rs[N*20];
10 void add(int x,int y){
11     edge[E].nex=head[x];
12     edge[E].to=y;
13     head[x]=E++;
14 }
15 void update(int k1,int &k2,int l,int r,int x){
16     k2=++V;
17     if (l==r){
18         f[k2]=f[k1]+1;
19         return;
20     }
21     ls[k2]=ls[k1];
22     rs[k2]=rs[k1];
23     if (x<=mid)update(ls[k1],ls[k2],l,mid,x);
24     else update(rs[k1],rs[k2],mid+1,r,x);
25     f[k2]=f[ls[k2]]+f[rs[k2]];
26 }
27 int query(int l,int r,int x){
28     if(l==r)return l;
29     int s=0;
30     for(int i=1;i<=t;i++)s+=f[ls[zh[i]]];
31     for(int i=1;i<=t;i++)s-=f[ls[fu[i]]];
32     if (x<=s){
33         for(int i=1;i<=t;i++)zh[i]=ls[zh[i]];
34         for(int i=1;i<=t;i++)fu[i]=ls[fu[i]];
35         query(l,mid,x);
36     }
37     else{
38         for(int i=1;i<=t;i++)zh[i]=rs[zh[i]];
39         for(int i=1;i<=t;i++)fu[i]=rs[fu[i]];
40         query(mid+1,r,x-s);
41     }
42 }
43 void dfs(int k,int f,int s){
44     fa[k]=f;
45     sh[k]=s;
46     sz[k]=1;
47     for(int i=head[k];i!=-1;i=edge[i].nex)
48         if (edge[i].to!=f){
49             dfs(edge[i].to,k,s+1);
50             sz[k]+=sz[edge[i].to];
51             if (sz[ma[k]]<sz[edge[i].to])ma[k]=edge[i].to;
52         }
53 }
54 void dfs2(int k,int t){
55     top[k]=t;
56     id[k]=++x;
57     update(r[x-1],r[x],1,n,a[k]);
58     if (ma[k])dfs2(ma[k],t);
59     for(int i=head[k];i!=-1;i=edge[i].nex)
60         if ((edge[i].to!=fa[k])&&(edge[i].to!=ma[k]))dfs2(edge[i].to,edge[i].to);
61 }
62 void query(int x,int y){
63     while (top[x]!=top[y]){
64         if (sh[top[x]]<sh[top[y]])swap(x,y);
65         zh[++t]=r[id[x]];
66         fu[t]=r[id[top[x]]-1];
67         x=fa[top[x]];
68     }
69     if (id[x]>id[y])swap(x,y);
70     zh[++t]=r[id[y]];
71     fu[t]=r[id[x]-1];
72 }
73 int main(){
74     scanf("%d%d",&n,&m);
75     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
76     memcpy(b,a,sizeof(b));
77     sort(b+1,b+n+1);
78     for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+n+1,a[i])-b;
79     memset(head,-1,sizeof(head));
80     for(int i=1;i<n;i++){
81         scanf("%d%d",&x,&y);
82         add(x,y);
83         add(y,x);
84     }
85     dfs(1,0,0);
86     x=0;
87     dfs2(1,1);
88     for(int i=1;i<=m;i++){
89         scanf("%d%d%d",&x,&y,&z);
90         t=0;
91         query(x^ans,y);
92         printf("%d\n",ans=b[query(1,n,z)]);
93     }
94 }
View Code

 

例题6:[bzoj1146]网络管理(树上动态第k小模板题)

  题意:询问给定树动态数链第k小

  1.树链剖分后同例题2(在线)(代码只有做法1)

技术图片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 100005
  4 #define L (k<<1)
  5 #define R (L+1)
  6 #define mid (l+r>>1)
  7 #define s(p) ch[k][p]
  8 struct ji{
  9     int nex,to;
 10 }edge[N<<1];
 11 int E,n,m,p,x,y,head[N],a[N],fa[N],sh[N],top[N],ma[N],id[N];
 12 int V,ro[N<<2],sz[N*50],sum[N*50],ra[N*50],v[N*50],ch[N*50][2];
 13 void add_edge(int x,int y){
 14     edge[E].nex=head[x];
 15     edge[E].to=y;
 16     head[x]=E++; 
 17 }
 18 void up(int k){
 19     sz[k]=sz[s(0)]+sz[s(1)]+sum[k];
 20 }
 21 void rotate(int &k,int x,int p){
 22     s(p)=ch[x][p^1];
 23     ch[x][p^1]=k;
 24     up(k);
 25     up(k=x);
 26 }
 27 void add(int &k,int x){
 28     if (!k){
 29         v[k=++V]=x;
 30         ra[k]=rand();
 31         sz[k]=0; 
 32     }
 33     sz[k]++;
 34     if (v[k]==x){
 35         sum[k]++;
 36         return;
 37     }
 38     bool p=(v[k]<x);
 39     add(s(p),x);
 40     if (ra[k]>ra[s(p)])rotate(k,s(p),p);
 41 }
 42 void del(int &k,int x){
 43     sz[k]--;
 44     if (v[k]==x){
 45         if (--sum[k])return;
 46         sum[k]++;
 47         if (s(0)*s(1)==0)k=s(0)+s(1);
 48         else{
 49             bool p=(ra[s(0)]>ra[s(1)]);
 50             rotate(k,s(p),p);
 51             del(k,x);
 52         }
 53         return;
 54     }
 55     del(s(v[k]<x),x);
 56 }
 57 int query(int k,int x){
 58     if (!k)return 0;
 59     if (v[k]==x)return sum[k]+sz[s(1)];
 60     bool p=(v[k]<x);
 61     return query(s(p),x)+(p^1)*(sum[k]+sz[s(1)]);
 62 }
 63 void update(int k,int l,int r,int x,int y,int z){
 64     if (y!=-1)del(ro[k],y);
 65     add(ro[k],z);
 66     if (l==r)return;
 67     if (x<=mid)update(L,l,mid,x,y,z);
 68     else update(R,mid+1,r,x,y,z);
 69 }
 70 int query(int k,int l,int r,int x,int y,int z){
 71     if ((l>y)||(x>r))return 0;
 72     if ((x<=l)&&(r<=y))return query(ro[k],z);
 73     return query(L,l,mid,x,y,z)+query(R,mid+1,r,x,y,z);
 74 }
 75 void dfs(int k,int f,int s){
 76     fa[k]=f;
 77     sh[k]=s;
 78     sz[k]=1;
 79     for(int i=head[k];i!=-1;i=edge[i].nex)
 80         if (edge[i].to!=f){
 81             dfs(edge[i].to,k,s+1);
 82             sz[k]+=sz[edge[i].to];
 83             if (sz[ma[k]]<sz[edge[i].to])ma[k]=edge[i].to;
 84         }
 85 }
 86 void dfs2(int k,int t){
 87     top[k]=t;
 88     id[k]=++x;
 89     update(1,1,n,x,-1,a[k]);
 90     if (ma[k])dfs2(ma[k],t);
 91     for(int i=head[k];i!=-1;i=edge[i].nex)
 92         if ((edge[i].to!=fa[k])&&(edge[i].to!=ma[k]))dfs2(edge[i].to,edge[i].to);
 93 }
 94 int query(int x,int y,int z){
 95     int ans=0;
 96     while (top[x]!=top[y]){
 97         if (sh[top[x]]<sh[top[y]])swap(x,y);
 98         ans+=query(1,1,n,id[top[x]],id[x],z);
 99         x=fa[top[x]];
100     }
101     if (id[x]>id[y])swap(x,y);
102     return ans+query(1,1,n,id[x],id[y],z);
103 }
104 int find(){
105     int l=0,r=100000000;
106     while (l<r){
107         int m=(l+r+1>>1);
108         if (query(x,y,m)>=p)l=m;
109         else r=m-1;
110     }
111     return l;
112 }
113 int main(){
114     srand(time(0));
115     scanf("%d%d",&n,&m);
116     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
117     memset(head,-1,sizeof(head));
118     for(int i=1;i<n;i++){
119         scanf("%d%d",&x,&y);
120         add_edge(x,y);
121         add_edge(y,x);
122     }
123     dfs(1,0,0);
124     x=0;
125     dfs2(1,1);
126     for(int i=1;i<=m;i++){
127         scanf("%d%d%d",&p,&x,&y);
128         if (!p){
129             update(1,1,n,id[x],a[x],y);
130             a[x]=y;
131             continue;
132         }
133         if (query(x,y,0)<p)printf("invalid request!\n");
134         else printf("%d\n",find());
135     }
136 }
View Code

  2.我太菜了,欢迎评论orz

 

总结(瞎扯淡)

  0.以上做法中一种做法属于标准做法,而且通常比较好写且不是特别难想

  1.将区间第k小/大转化为存在k个数小于等于/大于等于它且最小/大的数

  2.第k小问题比较难以解决是因为其不支持区间合并或区间合并复杂度较高

  3.数据结构是个好东西

第k小问题

标签:string   ++   name   check   网络管理   uniq   rand   algorithm   网络   

原文地址:https://www.cnblogs.com/PYWBKTDA/p/11375340.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!