第k小问题

例题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 }

  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 }

  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 }

  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 }

  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 }

  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 }

  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 }

  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 }

  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 }

  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 }

例题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 }

  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 }

例题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 }

  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 }

例题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 }

  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 }

例题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 }

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

总结(瞎扯淡):

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

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

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

  3.数据结构是个好东西

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

时间: 2024-08-07 17:58:36

第k小问题的相关文章

COGS 930. [河南省队2012] 找第k小的数

题目描述 看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2,A3,...,AN, 现在有M个询问,每个询问都是Ai...Aj中第k小的数等于多少. 输入格式 第一行两个正整数N,M. 第二行N个数,表示序列A1,A2,...,AN. 紧着的M行,每行三个正整数i,j,k(k≤j-i+1),表示 询问Ai...Aj中第k小的数等于多少. 输出格式 共输出M行,第i行输出第i个询问的答案. 样例输入1: 4 3 4 1 2 3 1 3 1 2 4 3 1 4 4 样例输出1: 1

bzoj3882 [Wc2015]K小割

Description Input Output Sample Input 3 3 1 3 100 1 2 3 2 3 4 1 3 5 Sample Output 8 9 12 -1 正解:暴搜+堆+最小割. 我觉得这道题真是毒瘤的可以了,正解要写$3$个程序才能过.. $task1$: $n<=10,m<=20$,暴搜即可. $task2$: $s$向除了$t$以外其他点连边,其他点向$t$连边. 最小割就是每个点的两条边取最小值然后相加. 考虑用堆来维护$k$小割,我们用类似于$k$短路的

cogs930.[河南省队2012] 找第k小的数

930. [河南省队2012] 找第k小的数 ★★★   输入文件:kth.in   输出文件:kth.out   简单对比 时间限制:1 s   内存限制:128 MB 题目描述 看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2,A3,...,AN, 现在有M个询问,每个询问都是Ai...Aj中第k小的数等于多少. 输入格式 第一行两个正整数N,M.第二行N个数,表示序列A1,A2,...,AN.紧着的M行,每行三个正整数i,j,k(k≤j-i+1),表示 询问Ai...Aj

Bzoj3065 带插入区间K小值

Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 3436  Solved: 1103 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少.这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问.这时伏

查找第K小的数 BFPRT算法

BFPRT算法是解决从n个数中选择第k大或第k小的数这个经典问题的著名算法,但很多人并不了解其细节.本文将首先介绍求解这个第k小数字问题的几个思路,然后重点介绍在最坏情况下复杂度仍然为O(n)的BFPRT算法. 一 基本思路 关于选择第k小的数有许多方法 将n个数排序(比如快速排序或归并排序),选取排序后的第k个数,时间复杂度为O(nlogn). 维护一个k个元素的最大堆,存储当前遇到的最小的k个数,时间复杂度为O(nlogk).这种方法同样适用于海量数据的处理. 部分的快速排序(快速选择算法)

BZOJ 3065 带插入区间K小值 替罪羊树套线段树

题目大意:带插入,单点修改的区间k小值在线查询. 思路:本年度做过最酸爽的题. 树套树的本质是一个外层不会动的树来套一个内层会动(或不会动)的树.两个树的时间复杂度相乘也就是差不多O(nlog^2n)左右.但是众所周知,高级数据结构经常会伴有庞大的常数,所以一般来说树套树的常数也不会小到哪去.所以在做这种题的时候先不要考虑常数的问题... 为什么要用替罪羊树呢?因为一般的平衡树都是会动的,这就很难办了.外层的树动了之后,内层的树肯定也是会动的.很显然,一般的二叉平衡树会经常会旋转,这样在动外层的

多个有序数列中查找第k小值

问题描述:现有n个有序序列如(2,3,9),(3,5,11,23),(1,4,7,9,15,17,20),(8,15,35,9),(20,30,40),请求出第k小值. 问题分析:可用多路归并排序将所有序列进行排序后取第k个值,但是只要求求出第k小值将所有数组排序未免显得有点浪费,所以我们可以使用包含k个元素的堆完成,对于每组元素取出前k小的,依次进行比较,得到总的前k小 执行步骤: 一.建初堆:从第一组数中取出前k小的元素建初始大根堆(若不足k个则取全部元素), 二. 1 .补充堆:若堆中元素

现在有m组n个有序数组,例如{1,2,3,4},{2,3,4,6},{1,3,5,7},在这些数组中选择第k小的数据,然后返回这个值

问题描述:现在有m组n个有序数组,例如{1,2,3,4},{2,3,4,6},{1,3,5,7},在这些数组中选择第k小的数据,然后返回这个值 思路:参照两个数组归并的过程,每次选取最小的数据进行比较 1,定义选取位置数组index[m],初始化为0 2,每次根据index[m]寻找到第l_row个数组,确保当前时刻的第l_row数组的当前位置为最小值:寻找时确保index[i]的值小于n 3,把最小值取出,index[l_row]自增1 4,逐次寻找,知道找到第k个为止 1 public st

顺序统计:寻找序列中第k小的数

最直观的解法,排序之后取下标为k的值即可. 但是此处采取的方法为类似快速排序分块的方法,利用一个支点将序列分为两个子序列(支点左边的值小于支点的值,支点右边大于等于支点的值). 如果支点下标等于k,则支点就是查找的值,如果支点的下标大于k,则在左子序列里继续寻找,如果支点下标小于k,则继续在支点右子序列里面继续寻找第(k-支点下标)小的值. c#实现算法如下: public class FindSpecialOrderElement<T> where T : IComparable<T&

poj 2104主席树求区间第k小

POJ - 2104 题意:求区间第k小 思路:无修改主席树 AC代码: #include "iostream" #include "iomanip" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set&