洛谷 P3285 [SCOI2014]方伯伯的OJ
看到这题,第一眼:平衡树水题,随便做一做好了
然后....我在花了n个小时去调试(维护平衡树父节点)之后,...
调了三个小时后,第一次失败的代码(只能查找排名为k的用户编号,不能根据编号查排名)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<algorithm> #include<queue> #include<map> using namespace std; int r[300100],lx[300100],rx[300100],sz[300100],ch[300100][2]; map<int,int> ma,ma2; queue<int> q; int getnode() { int t=q.front();q.pop();return t; } void delnode(int x) { q.push(x); } int rand1() { static int x=131; return x=(48271LL*x+1)%2147483647; } void upd(int x) { //sz[x]=sz[ch[x][0]]+sz[ch[x][1]]; sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+rx[x]-lx[x]+1; } int root; int merge(int a,int b) { if(!a||!b) return a+b; if(r[a]<r[b]) { ch[a][1]=merge(ch[a][1],b);upd(a); return a; } else { ch[b][0]=merge(a,ch[b][0]);upd(b); return b; } } typedef pair<int,int> P; P split(int a,int n)//a的前n个放入first,剩余放入second { if(!a) return P(0,0); int s=sz[ch[a][0]];P t; if(s>=n) { t=split(ch[a][0],n);ch[a][0]=t.second;upd(a); return P(t.first,a); } else { t=split(ch[a][1],n-s-1);ch[a][1]=t.first;upd(a); return P(a,t.second); } } P find(int x) { int num=root;P t;t.second=0; while(1) { if(lx[num]>x) num=ch[num][0]; else if(rx[num]<x) t.second+=sz[ch[num][0]]+rx[num]-lx[num]+1,num=ch[num][1]; else break; } t.first=num; return t; } P find_kth(int k) { int num=root,ls;P t;t.second=0; while(1) { ls=sz[ch[num][0]]; if(ls>=k) num=ch[num][0]; else if(ls+rx[num]-lx[num]+1>=k) break; else t.second+=ls+rx[num]-lx[num]+1,num=ch[num][1]; } t.first=num; return t; } int newnode(int L,int R) { int t=getnode();r[t]=rand1();lx[t]=L;rx[t]=R;sz[t]=R-L+1; return t; } int n,m,lans; int main() { P t1,t2,t3; int x,y,t,ta,tb,tc,i,idx; for(i=1;i<300000;i++) q.push(i); scanf("%d%d",&n,&m); root=getnode();lx[root]=1;rx[root]=n;sz[root]=n;r[root]=rand1(); for(i=1;i<=m;i++) { scanf("%d",&idx); if(idx==1) { scanf("%d%d",&x,&y);x-=lans;y-=lans; if(ma.count(x))//ma记录用户编号对应的虚拟编号 { t=ma[x];ma.erase(x);ma[y]=x; ma2[t]=y;//ma2反过来 } else { t=x;ma[y]=x;ma2[t]=y; } //t1=find(y);lans=t1.second+y-lx[t1.first]+1; t1=find(t);lans=t1.second+t-lx[t1.first]+1; printf("%d\n",lans); } else if(idx==2) { scanf("%d",&x);x-=lans;x=ma.count(x)?ma[x]:x; t1=find(x);t=t1.second+x-lx[t1.first]+1; t2=split(root,t1.second);t3=split(t2.second,rx[t1.first]-lx[t1.first]+1); if(lx[t3.first]!=x) { ta=newnode(lx[t3.first],x-1); } else ta=0; tb=newnode(x,x); if(rx[t3.first]!=x) { tc=newnode(x+1,rx[t3.first]); } else tc=0; delnode(t3.first); root=merge(merge(tb,t2.first),merge(ta,merge(tc,t3.second))); printf("%d\n",t);lans=t; } else if(idx==3) { scanf("%d",&x);x-=lans;x=ma.count(x)?ma[x]:x; t1=find(x);t=t1.second+x-lx[t1.first]+1; t2=split(root,t1.second);t3=split(t2.second,rx[t1.first]-lx[t1.first]+1); if(lx[t3.first]!=x) { ta=newnode(lx[t3.first],x-1); } else ta=0; tb=newnode(x,x); if(rx[t3.first]!=x) { tc=newnode(x+1,rx[t3.first]); } else tc=0; root=merge(merge(t2.first,ta),merge(tc,merge(t3.second,tb))); printf("%d\n",t);lans=t; } else if(idx==4) { scanf("%d",&x);x-=lans;x=ma.count(x)?ma[x]:x; t1=find_kth(x); t=t1.first+t1.second-lx[t1.first]+1; lans=ma2.count(t)?ma2[t]:t; printf("%d\n",lans); } } return 0; }
又是四个小时后,第二次失败的代码(由于只记录了编号对应的root或ch[][]中某位置的指针,拆分某节点时无法一并改变这些关联的指针)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<algorithm> #include<map> #include<queue> #define N 100005 using namespace std; typedef pair<int,int> P; typedef pair<P,int*> P2; int lx[N],rx[N],sz[N],fa[N],ch[N][2],r[N]; map<P,int*> ma; queue<int> q; int root; int rand1() { static int x=471; return x=(48271LL*x+1)%2147483647; } int getnode() { int t=q.front();q.pop();r[t]=rand1(); lx[t]=rx[t]=sz[t]=fa[t]=ch[t][0]=ch[t][1]=0; return t; } void delnode(int x) {q.push(x);} void upd(int x) {sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+rx[x]-lx[x]+1;} P split(int a,int n) { if(!a) return P(0,0); int ls=sz[ch[a][0]];P t; if(n<=ls) { t=split(ch[a][0],n);ch[a][0]=t.second; if(ch[a][0]) fa[ch[a][0]]=a; upd(a);t.second=a; } else { t=split(ch[a][1],n-ls-1);ch[a][1]=t.first; if(ch[a][1]) fa[ch[a][1]]=a; upd(a);t.first=a; } return t; } int merge(int a,int b) { if(!a||!b) return a+b; if(r[a]<r[b]) { ch[a][1]=merge(ch[a][1],b);upd(a); if(ch[a][1]) fa[ch[a][1]]=a; return a; } else { ch[b][0]=merge(a,ch[b][0]);upd(b); if(ch[b][0]) fa[ch[b][0]]=b; return b; } } int n,m; int *get_pointer(int x) { if(x==root) return &root; else if(x==ch[fa[x]][0]) return &ch[fa[x]][0]; else return &ch[fa[x]][1]; } void split_node_of_user(int x) { P2 t;int l,r,t1,t2,t3,t4,t5,oo; t=*ma.lower_bound(P(x,0));ma.erase(t.first); l=t.first.second;r=t.first.first;int &o=*t.second; t1=0,t2=0,t3=0,t4=ch[o][0],t5=ch[o][1]; if(x>l) {t1=getnode();lx[t1]=l;rx[t1]=x-1;sz[t1]=x-l;} t2=getnode();lx[t2]=rx[t2]=x;sz[t2]=1; if(x<r) {t3=getnode();lx[t3]=x+1;rx[t3]=r;sz[t3]=r-x;} oo=o;o=merge(merge(t4,t1),merge(merge(t2,t3),t5));fa[o]=fa[oo]; delnode(oo); if(x>l) ma[P(x-1,l)]=get_pointer(t1); ma[P(x,x)]=get_pointer(t2); if(x<r) ma[P(r,x+1)]=get_pointer(t3); } int get_rank(int o) { int ans=sz[ch[o][0]]; while(o!=root) { if(o==ch[fa[o]][1]) ans+=rx[fa[o]]-lx[fa[o]]+1+sz[ch[fa[o]][0]]; o=fa[o]; } return ans; } int find_kth(int k) { int o=root,ls,ns; while(1) { ls=sz[ch[o][0]];ns=rx[o]-lx[o]+1; if(ls>=k) o=ch[o][0]; else if(ls+ns>=k) break; else k-=(ls+ns),o=ch[o][1]; } return lx[o]+k-1; } int get_rank_of_user(int x) { P2 t=*ma.lower_bound(P(x,0)); return get_rank(*t.second)+x-lx[*t.second]; } int main() { int i,idx,x,y,t,lans=0;int *tx;P t1,t2; for(i=1;i<N;++i) q.push(i); scanf("%d%d",&n,&m); root=getnode();lx[root]=1;rx[root]=n;sz[root]=n;ma.insert(P2(P(n,1),&root)); for(i=1;i<=m;i++) { scanf("%d",&idx); if(idx==1) { scanf("%d%d",&x,&y);x-=lans;y-=lans;lans=get_rank_of_user(x)+1; split_node_of_user(x);tx=ma[P(x,x)];lx[*tx]=rx[*tx]=y; ma[P(y,y)]=tx;ma.erase(P(x,x)); printf("%d\n",lans); } else if(idx==2) { scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1; split_node_of_user(x);t=get_rank(*ma[P(x,x)]); t1=split(root,t);t2=split(t1.second,1); root=merge(merge(t2.first,t1.first),t2.second); printf("%d\n",lans); } else if(idx==3) { scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1; split_node_of_user(x);t=get_rank(*ma[P(x,x)]); t1=split(root,t);t2=split(t1.second,1); root=merge(merge(t1.first,t2.second),t2.first); printf("%d\n",lans); } else if(idx==4) { scanf("%d",&x);x-=lans; printf("%d\n",find_kth(x)); } } return 0; }
该改的改完之后(包括父节点维护),玄学失败N次的代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<algorithm> #include<map> #include<queue> #define N 300005 using namespace std; typedef pair<int,int> P; typedef pair<P,int> P2; int lx[N],rx[N],sz[N],fa[N],ch[N][2],r[N]; map<P,int> ma; queue<int> q; int root; int rand1() { static int x=471; return x=(48271LL*x+1)%2147483647; } int getnode() { int t=q.front();q.pop();r[t]=rand1(); lx[t]=rx[t]=sz[t]=fa[t]=ch[t][0]=ch[t][1]=0; return t; } void delnode(int x) {q.push(x);} void upd(int x) {sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+rx[x]-lx[x]+1;} P split(int a,int n) { if(!a) return P(0,0); int ls=sz[ch[a][0]];P t; if(n<=ls) { t=split(ch[a][0],n);ch[a][0]=t.second; if(ch[a][0]) fa[ch[a][0]]=a; upd(a);t.second=a; } else { t=split(ch[a][1],n-ls-(rx[a]-lx[a]+1));ch[a][1]=t.first; if(ch[a][1]) fa[ch[a][1]]=a; upd(a);t.first=a; } return t; } int merge(int a,int b) { if(!a||!b) return a+b; if(r[a]<r[b]) { ch[a][1]=merge(ch[a][1],b);upd(a); if(ch[a][1]) fa[ch[a][1]]=a; return a; } else { ch[b][0]=merge(a,ch[b][0]);upd(b); if(ch[b][0]) fa[ch[b][0]]=b; return b; } } int n,m; int& get_ref(int x) { if(x==root) return root; if(x==ch[fa[x]][0]) return ch[fa[x]][0]; return ch[fa[x]][1]; } void split_node_of_user(int x) { P2 t;int l,r,t1,t2,t3,t4,t5,oo; t=*ma.lower_bound(P(x,0));ma.erase(t.first); l=t.first.second;r=t.first.first;int &o=get_ref(t.second); t1=0,t2=0,t3=0,t4=ch[o][0],t5=ch[o][1]; if(x>l) {t1=getnode();lx[t1]=l;rx[t1]=x-1;sz[t1]=x-l;} t2=getnode();lx[t2]=rx[t2]=x;sz[t2]=1; if(x<r) {t3=getnode();lx[t3]=x+1;rx[t3]=r;sz[t3]=r-x;} oo=o;o=merge(merge(t4,t1),merge(merge(t2,t3),t5));fa[o]=fa[oo]; delnode(oo); if(x>l) ma[P(x-1,l)]=t1; ma[P(x,x)]=t2; if(x<r) ma[P(r,x+1)]=t3; } int get_rank(int o) { int ans=sz[ch[o][0]]; while(o!=root) { if(o==ch[fa[o]][1]) ans+=rx[fa[o]]-lx[fa[o]]+1+sz[ch[fa[o]][0]]; o=fa[o]; } return ans; } int find_kth(int k) { int o=root,ls,ns; while(1) { ls=sz[ch[o][0]];ns=rx[o]-lx[o]+1; if(ls>=k) o=ch[o][0]; else if(ls+ns>=k) {k-=ls;break;} else k-=(ls+ns),o=ch[o][1]; } return lx[o]+k-1; } int get_rank_of_user(int x) { P2 t=*ma.lower_bound(P(x,0)); return get_rank(t.second)+x-lx[t.second]; } int main() { int i,idx,x,y,t,lans=0;P t1,t2; for(i=1;i<N;++i) q.push(i); scanf("%d%d",&n,&m); root=getnode();lx[root]=1;rx[root]=n;sz[root]=n;ma.insert(P2(P(n,1),root)); for(i=1;i<=m;i++) { scanf("%d",&idx); if(idx==1) { scanf("%d%d",&x,&y);x-=lans;y-=lans;lans=get_rank_of_user(x)+1; split_node_of_user(x);t=ma[P(x,x)];lx[t]=rx[t]=y; ma[P(y,y)]=t;ma.erase(P(x,x)); printf("%d\n",lans); } else if(idx==2) { scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1; split_node_of_user(x);t=get_rank(ma[P(x,x)]); t1=split(root,t);t2=split(t1.second,1); root=merge(merge(t2.first,t1.first),t2.second); printf("%d\n",lans); } else if(idx==3) { scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1; split_node_of_user(x);t=get_rank(ma[P(x,x)]); t1=split(root,t);t2=split(t1.second,1); root=merge(merge(t1.first,t2.second),t2.first); printf("%d\n",lans); } else if(idx==4) { scanf("%d",&x);x-=lans; printf("%d\n",find_kth(x)); } } return 0; }
AC代码。AC代码与上面一份代码唯一的区别是在第147行多了一句更新lastans...而且常数巨大233333
1 #include<cstdio> 2 #include<algorithm> 3 #include<map> 4 #include<queue> 5 #define N 300005 6 using namespace std; 7 typedef pair<int,int> P; 8 typedef pair<P,int> P2; 9 10 int lx[N],rx[N],sz[N],fa[N],ch[N][2],r[N]; 11 map<P,int> ma; 12 queue<int> q; 13 int root; 14 int rand1() 15 { 16 static int x=471; 17 return x=(48271LL*x+1)%2147483647; 18 } 19 int getnode() 20 { 21 int t=q.front();q.pop();r[t]=rand1(); 22 lx[t]=rx[t]=sz[t]=fa[t]=ch[t][0]=ch[t][1]=0; 23 return t; 24 } 25 void delnode(int x) {q.push(x);} 26 void upd(int x) {sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+rx[x]-lx[x]+1;} 27 28 P split(int a,int n) 29 { 30 if(!a) return P(0,0); 31 int ls=sz[ch[a][0]];P t; 32 if(n<=ls) 33 { 34 t=split(ch[a][0],n);ch[a][0]=t.second; 35 if(ch[a][0]) fa[ch[a][0]]=a; 36 upd(a);t.second=a; 37 } 38 else 39 { 40 t=split(ch[a][1],n-ls-(rx[a]-lx[a]+1));ch[a][1]=t.first; 41 if(ch[a][1]) fa[ch[a][1]]=a; 42 upd(a);t.first=a; 43 } 44 return t; 45 } 46 47 int merge(int a,int b) 48 { 49 if(!a||!b) return a+b; 50 if(r[a]<r[b]) 51 { 52 ch[a][1]=merge(ch[a][1],b);upd(a); 53 if(ch[a][1]) fa[ch[a][1]]=a; 54 return a; 55 } 56 else 57 { 58 ch[b][0]=merge(a,ch[b][0]);upd(b); 59 if(ch[b][0]) fa[ch[b][0]]=b; 60 return b; 61 } 62 } 63 int n,m; 64 int& get_ref(int x) 65 { 66 if(x==root) return root; 67 if(x==ch[fa[x]][0]) return ch[fa[x]][0]; 68 return ch[fa[x]][1]; 69 } 70 71 void split_node_of_user(int x) 72 { 73 P2 t;int l,r,t1,t2,t3,t4,t5,oo; 74 t=*ma.lower_bound(P(x,0));ma.erase(t.first); 75 l=t.first.second;r=t.first.first;int &o=get_ref(t.second); 76 t1=0,t2=0,t3=0,t4=ch[o][0],t5=ch[o][1]; 77 if(x>l) {t1=getnode();lx[t1]=l;rx[t1]=x-1;sz[t1]=x-l;} 78 t2=getnode();lx[t2]=rx[t2]=x;sz[t2]=1; 79 if(x<r) {t3=getnode();lx[t3]=x+1;rx[t3]=r;sz[t3]=r-x;} 80 oo=o;o=merge(merge(t4,t1),merge(merge(t2,t3),t5));fa[o]=fa[oo]; 81 delnode(oo); 82 if(x>l) ma[P(x-1,l)]=t1; 83 ma[P(x,x)]=t2; 84 if(x<r) ma[P(r,x+1)]=t3; 85 } 86 int get_rank(int o) 87 { 88 int ans=sz[ch[o][0]]; 89 while(o!=root) 90 { 91 if(o==ch[fa[o]][1]) ans+=rx[fa[o]]-lx[fa[o]]+1+sz[ch[fa[o]][0]]; 92 o=fa[o]; 93 } 94 return ans; 95 } 96 int find_kth(int k) 97 { 98 int o=root,ls,ns; 99 while(1) 100 { 101 ls=sz[ch[o][0]];ns=rx[o]-lx[o]+1; 102 if(ls>=k) o=ch[o][0]; 103 else if(ls+ns>=k) {k-=ls;break;} 104 else k-=(ls+ns),o=ch[o][1]; 105 } 106 return lx[o]+k-1; 107 } 108 int get_rank_of_user(int x) 109 { 110 P2 t=*ma.lower_bound(P(x,0)); 111 return get_rank(t.second)+x-lx[t.second]; 112 } 113 int main() 114 { 115 int i,idx,x,y,t,lans=0;P t1,t2; 116 for(i=1;i<N;++i) q.push(i); 117 scanf("%d%d",&n,&m); 118 root=getnode();lx[root]=1;rx[root]=n;sz[root]=n;ma.insert(P2(P(n,1),root)); 119 for(i=1;i<=m;i++) 120 { 121 scanf("%d",&idx); 122 if(idx==1) 123 { 124 scanf("%d%d",&x,&y);x-=lans;y-=lans;lans=get_rank_of_user(x)+1; 125 split_node_of_user(x);t=ma[P(x,x)];lx[t]=rx[t]=y; 126 ma[P(y,y)]=t;ma.erase(P(x,x)); 127 printf("%d\n",lans); 128 } 129 else if(idx==2) 130 { 131 scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1; 132 split_node_of_user(x);t=get_rank(ma[P(x,x)]); 133 t1=split(root,t);t2=split(t1.second,1); 134 root=merge(merge(t2.first,t1.first),t2.second); 135 printf("%d\n",lans); 136 } 137 else if(idx==3) 138 { 139 scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1; 140 split_node_of_user(x);t=get_rank(ma[P(x,x)]); 141 t1=split(root,t);t2=split(t1.second,1); 142 root=merge(merge(t1.first,t2.second),t2.first); 143 printf("%d\n",lans); 144 } 145 else if(idx==4) 146 { 147 scanf("%d",&x);x-=lans;lans=find_kth(x); 148 printf("%d\n",lans); 149 } 150 } 151 return 0; 152 }
从洛谷掏的数据233333
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
n 1 1000 2 100000 3 100000 4 100000 5 100000000 6 100000000 7 100000000 8 100000000 9 100000000 10 100000000 :1 1 3 2 2 3 2 4 2 5 4 6 3 7 2 8 2 9 3 10 3 :2 01 00000740 02 00080429 03 00079678 04 00058089 05 44174437 06 98466201 07 25431148 08 40131901 09 43505820 10 03752119 :3 01 3 02 2 03 3 04 3 05 2 06 3 07 4 08 3 09 2 10 3 :4 01 000001238 02 000120026 03 000171419 04 000068300 05 094123098 06 107162571 07 061586793 08 069985796 09 083066732 10 005367888 :5 1 3 2 4 3 1 4 4 5 3 6 3 7 2 8 2 9 1 10 2 :6 01 000000907 02 000053848 03 000186311 04 000015145 05 069092662 06 100076086 07 112422962 08 112340967 09 107295244 10 055061511 :7 01 3 02 3 03 000192415 04 2 05 3 06 4 07 4 08 2 09 139958623 10 3 :8 01 000000762 02 000089049 03 4 04 000090777 05 038934093 06 146581036 07 103255266 08 096193795 09 2 10 151256841 :9 01 1 02 4 03 000191572 04 4 05 4 06 3 07 4 08 2 09 073904286 10 2 :10 01 000000984 02 000124275 03 3 04 000134293 05 062449488 06 126079909 07 075280761 08 031377328 09 3 10 099020316 :11 01 000001358 02 2 03 000125643 04 3 05 2 06 4 07 3 08 3 09 077311124 10 3 :12 01 1 02 062617 03 4 04 051355 05 060130743 06 120950877 07 103836077 08 089326104 09 3 10 093010296 :13 01 02 03 04 05 06 07 08 09 10
具体思路跟NOIP2017D2T3很像....也可以当做平衡树动态开点的某种通用方法...不过细节跟线段树动态开点比的话就23333...
至于具体动态查询编号对应排名的话,用map记录编号对应的节点编号(或一段连续编号对应的同一个节点编号,[l,r]这一段连续编号用P(r,l)表示),然后非旋treap维护序列,记录一下每个节点的父节点,这样就可以根据节点编号查询排名了
(记一下64到85行)