标签:string ++ name check 网络管理 uniq rand algorithm 网络
题意:询问给定序列静态区间第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)(在线)
题意:询问给定序列动态(单点修改)区间第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 }
题意:询问给定序列动态(单点修改和单点插入)区间第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 }
题意:询问给定序列动态(区间加入,不删除)区间第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 }
题意:询问给定树静态数链第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 }
题意:询问给定树动态数链第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.数据结构是个好东西
标签:string ++ name check 网络管理 uniq rand algorithm 网络
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11375340.html