NOIP的基本模板进阶
NOIP基本模板进阶
一.Treap
支持:
- 插入x
- 删除x(若有多个相同的数,因只删除一个)
- 查询x的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
- 查询排名为x的数
- 求x的前驱(前驱定义为小于x,且最大的数)
- 求x的后继(后继定义为大于x,且最小的数)
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> #include<cstdlib> using namespace std; #define INF 0x7fffffff #define N 100010 int n,tot,root; struct Treap { int l,r,val,len,cnt,siz; }a[N]; int New(int x) { a[++tot].val=x; a[tot].len=rand(); a[tot].cnt=a[tot].siz=1; return tot; } void Update(int p) { a[p].siz=a[a[p].l].siz+a[a[p].r].siz+a[p].cnt; } void Build() { New(-INF); New(INF); root=1; a[1].r=2; Update(root); } int GetRankByVal(int p,int k) { if(p==0) return 0; if(k==a[p].val) return a[a[p].l].siz+1; else if(k<a[p].val) return GetRankByVal(a[p].l,k); else return GetRankByVal(a[p].r,k)+a[a[p].l].siz+a[p].cnt; } int GetValByRank(int p,int rank) { if(p==0) return INF; if(a[a[p].l].siz>=rank) return GetValByRank(a[p].l,rank); else if(a[a[p].l].siz+a[p].cnt>=rank) return a[p].val; else return GetValByRank(a[p].r,rank-a[a[p].l].siz-a[p].cnt); } void zig(int &p) { int q=a[p].l; a[p].l=a[q].r; a[q].r=p; p=q; Update(a[p].r); Update(p); } void zag(int &p) { int q=a[p].r; a[p].r=a[q].l; a[q].l=p; p=q; Update(a[p].l); Update(p); } void Insert(int &p,int k) { if(p==0) { p=New(k); return; } if(k==a[p].val) { a[p].cnt++; Update(p); return; } if(k<a[p].val) { Insert(a[p].l,k); if(a[p].len<a[a[p].l].len) zig(p); } else { Insert(a[p].r,k); if(a[p].len<a[a[p].r].len) zag(p); } Update(p); } void Remove(int &p,int k) { if(p==0) return; if(k==a[p].val) { if(a[p].cnt>1) { a[p].cnt--; Update(p); return; } if(a[p].l||a[p].r) { if(a[p].r==0||a[a[p].l].len>a[a[p].r].len) { zig(p); Remove(a[p].r,k); } else { zag(p); Remove(a[p].l,k); } Update(p); } else p=0; return; } if(k<a[p].val) Remove(a[p].l,k); else Remove(a[p].r,k); Update(p); } int GetPre(int k) { int ans=1; int p=root; while(p) { if(k==a[p].val) { if(a[p].l>0) { p=a[p].l; while(a[p].r>0) p=a[p].r; ans=p; } break; } if(a[p].val<k&&a[p].val>a[ans].val) ans=p; if(k<a[p].val) p=a[p].l; else p=a[p].r; } return a[ans].val; } int GetNxt(int k) { int ans=2; int p=root; while(p) { if(k==a[p].val) { if(a[p].r>0) { p=a[p].r; while(a[p].l>0) p=a[p].l; ans=p; } break; } if(a[p].val>k&&a[p].val<a[ans].val) ans=p; if(k<a[p].val) p=a[p].l; else p=a[p].r; } return a[ans].val; } int main() { scanf("%d",&n); Build(); while(n--) { int x,k; scanf("%d%d",&k,&x); if(k==1) Insert(root,x); if(k==2) Remove(root,x); if(k==3) printf("%d\n",GetRankByVal(root,x)-1); if(k==4) printf("%d\n",GetValByRank(root,x+1)); if(k==5) printf("%d\n",GetPre(x)); if(k==6) printf("%d\n",GetNxt(x)); } return 0; }
二.非旋转Treap
支持普通Treap操作,区间翻转
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; #define N 100010 int n,tot,root,m; bool flag[N]; struct Treap { int val,len,siz,ch[2]; void clear() { ch[0]=ch[1]=siz=val=len=0; } }t[N]; void update(int p) { t[p].siz=t[t[p].ch[0]].siz+t[t[p].ch[1]].siz+1; } void pushdown(int p) { if(!flag[p]) return; swap(t[p].ch[0],t[p].ch[1]); if(t[p].ch[0]!=0) flag[t[p].ch[0]]^=1; if(t[p].ch[1]!=0) flag[t[p].ch[1]]^=1; flag[p]=0; } int merge(int x,int y) { if(!x||!y) return x+y; pushdown(x); pushdown(y); if(t[x].len<t[y].len) { t[x].ch[1]=merge(t[x].ch[1],y); update(x); return x; } else { t[y].ch[0]=merge(x,t[y].ch[0]); update(y); return y; } } void split_val(int p,int val,int &x,int &y) { if(!p) { x=y=0; return; } pushdown(p); if(t[p].val<=val) x=p,split_val(t[p].ch[1],val,t[p].ch[1],y); else y=p,split_val(t[p].ch[0],val,x,t[p].ch[0]); update(p); } void split_k(int p,int k,int &x,int &y) { if(!p) { x=y=0; return; } pushdown(p); if(t[t[p].ch[0]].siz<k) x=p,split_k(t[p].ch[1],k-t[t[p].ch[0]].siz-1,t[p].ch[1],y); else y=p,split_k(t[p].ch[0],k,x,t[p].ch[0]); update(p); } void Insert(int val) { int a,b; t[++tot].len=rand(); t[tot].val=val; t[tot].siz=1; split_val(root,val,a,b); root=merge(merge(a,tot),b); } void remove(int val) { int a,b,c,d; split_val(root,val-1,a,b); split_k(b,1,c,d); t[c].clear(); root=merge(a,d); } int getrank(int val) { int a,b,c; split_val(root,val-1,a,b); c=t[a].siz+1; root=merge(a,b); return c; } int getval(int &p,int k) { int a,b,c,d,e; split_k(p,k-1,a,b); split_k(b,1,c,d); e=t[c].val; p=merge(a,merge(c,d)); return e; } int getpre(int x) { int a,b,c; split_val(root,x-1,a,b); c=getval(a,t[a].siz); root=merge(a,b); return c; } int getnxt(int x) { int a,b,c; split_val(root,x,a,b); c=getval(b,1); root=merge(a,b); return c; } void coutt(int p) { if(!p) return; if(flag[p]!=0) pushdown(p); coutt(t[p].ch[0]); printf("%d ",t[p].val); coutt(t[p].ch[1]); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)//普通平衡树 Insert(i); while(m--) { int l,r,a,b,c; scanf("%d%d",&l,&r); split_k(root,r,b,c); split_k(b,l-1,a,b); flag[b]^=1; root=merge(a,merge(b,c)); } coutt(root); while(n--)//文艺平衡树 { int k,x; scanf("%d%d",&k,&x); if(k==1) Insert(x); if(k==2) remove(x); if(k==3) printf("%d\n",getrank(x)); if(k==4) printf("%d\n",getval(root,x)); if(k==5) printf("%d\n",getpre(x)); if(k==6) printf("%d\n",getnxt(x)); } }
三.权值线段树
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> using namespace std; #define N 200010 int m,n,idx,a[N],b[N],cnt[N<<2],u[N],idxx=1; void pushup(int p) { cnt[p]=cnt[p<<1]+cnt[p<<1|1]; } void update(int l,int r,int k,int v) { if(l==r) { cnt[k]++; return; } int mid=(l+r)>>1; if(v<=mid) update(l,mid,k<<1,v); if(v>mid) update(mid+1,r,k<<1|1,v); pushup(k); } int query(int l,int r,int k,int rank) { if(l==r) return l; int mid=(l+r)>>1; if(rank<=cnt[k<<1]) return query(l,mid,k<<1,rank); else return query(mid+1,r,k<<1|1,rank-cnt[k<<1]); } int main() { scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) { scanf("%d",&a[i]); b[i]=a[i]; } for(int i=1;i<=n;i++) scanf("%d",&u[i]); sort(b+1,b+m+1); int tot=unique(b+1,b+m+1)-b-1; for(int i=1;i<=m;i++) { int x=lower_bound(b+1,b+tot+1,a[i])-b; update(1,tot,1,x); while(i==u[idxx]) { printf("%d\n",b[query(1,tot,1,++idx)]); ++idxx; } } return 0; }