第k小问题

Posted pywbktda

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第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 
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]=ji0,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小问题的主要内容,如果未能解决你的问题,请参考以下文章

线性时间选择--用于解决第k大(小)元素问题(未补)

P2617 第K小(动态可持久化线段树)

少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小

区间第k小(分块 + 二分)

随机选择第k小元素随机快速排序-算法设计与分析实验四

随机选择第k小元素随机快速排序-算法设计与分析实验四