当初学 Splay树 所看过的,凭理解打过的代码
来源:互联网 发布:仓廪实则知礼节的例子 编辑:程序博客网 时间:2024/05/16 15:49
HDU 1890
这是我第一次接触Splay树时,所接触的代码。
那位大牛的博客我现在找不到了#。#。抱歉ing..
思路就是区间翻转,主要是将n个数通过树的先序访问保存下来。
这样旋转的时候就不会出现问题
代码:
//// 1890.cpp// ACM_HDU//// Created by ipqhjjybj on 13-8-27.// Copyright (c) 2013年 ipqhjjybj. All rights reserved.// 参考着别人Ac代码敲的//#include <cstdio>#include <algorithm>#include <map>using namespace std;struct SplayTree{ const static int maxn=111111; int n,tot,root; map<int,int> Map; int child[maxn][2]; int pre[maxn],size[maxn],flex[maxn]; int id[maxn]; struct node{ int id,val; bool operator < (const node & tmp) const{ return val<tmp.val||(val==tmp.val&&id<tmp.id); } }in[maxn]; void Pushup(int &x){ size[x]=size[child[x][0]]+size[child[x][1]]+1; } void Pushdown(int &x){ if(flex[x]){ flex[x]=0; flex[child[x][0]]^=1; flex[child[x][1]]^=1; swap(child[x][0],child[x][1]); } } void Del_root(){ int t=root; if(child[root][1]){ root=child[root][1]; Select(1,0); child[root][0]=child[t][0]; if(child[t][0]) pre[child[t][0]]=root; }else root=child[root][0]; pre[root]=0; Pushup(root); } // c==0 左旋 , c==1 右旋 inline void Rotate(int x, int c) { // 旋转, c=0 左旋, c=1 右旋 int y = pre[x]; Pushdown(y); Pushdown(x); child[y][!c] = child[x][c]; if ( child[x][c] ) pre[ child[x][c] ] = y; pre[x] = pre[y]; if ( pre[y] ) child[ pre[y] ][ child[pre[y]][1] == y ] = x; child[x][c] = y; pre[y] = x; Pushup(y); } void Splay(int x,int f){ // puts("fuck Splay"); Pushdown(x); while(pre[x]!=f){ // printf("f=%d pre[%d]=%d\n",f,x,pre[x]); int y=pre[x],z=pre[y]; Pushdown(z),Pushdown(y),Pushdown(x); if(pre[pre[x]]==f){ Rotate(x,child[pre[x]][0]==x); }else{ if ( child[z][0] == y ) { if ( child[y][0] == x ) Rotate(y, 1), Rotate(x, 1); else Rotate(x, 0), Rotate(x, 1); } else { if ( child[y][0] == x ) Rotate(x, 1), Rotate(x, 0); else Rotate(y, 0), Rotate(x, 0); } } } Pushup(x); if(f==0) root=x; } void Select(int k,int f){ int x=root; while(1){ Pushdown(x); if(k==size[child[x][0]]+1) break; if(k<=size[child[x][0]]) x=child[x][0]; else{ k-=size[child[x][0]]+1; x=child[x][1]; } } Splay(x,f); } void Newnode(int &x,int f){ //puts("fuck newnode"); x=++tot; child[x][0]=child[x][1]=0; pre[x]=f; flex[x]=0; size[x]=1; } void Build(int &x,int l,int r,int f){ if(l>r)return; int mid=(l+r)>>1; //puts("Fuck(Build)"); Newnode(x,f); Map[id[mid]]=x; Build(child[x][0],l,mid-1,x); Build(child[x][1],mid+1,r,x); Pushup(x); } void init(int _n){ n=_n; Map.clear(); root=tot=0; pre[0]=child[0][0]=child[0][1]=0; size[0]=flex[0]=0; for(int i=1;i<=n;i++){ scanf("%d",&in[i].val); in[i].id=i; } sort(in+1,in+1+n); for(int i=1;i<=n;i++) id[in[i].id]=i; Map[id[1]]=1; Map[id[n]]=2; Newnode(root,0); Newnode(child[root][1],root); Build(child[child[root][1]][0],2,n-1,child[root][1]); Pushup(child[root][1]); Pushup(root); } void solve(int n){ for(int i=1;i<=n;i++){ //printf("i=%d\n",i); //printf("Map[%d]=%d\n",i,Map[i]); Splay(Map[i],0); //printf("root=%d\n",root); printf("%d%c",i+size[child[root][0]],i==n?'\n':' '); flex[child[root][0]]^=1; Del_root(); } }}spt;int main(){ int n; while(scanf("%d",&n)&&n){ if(n==1){scanf("%*d");puts("1");continue;} spt.init(n); spt.solve(n); } return 0;}
HDU 3487
别人都说这是水题。。
设计到Splay的基本操作,区间翻转及区间插入。。
对[l,r]这段区间,要想获得的话,先将l-1这个节点翻转到根节点,再把r+1这个节点翻转到根节点之下。
这样KeyTree child[child[root][1]][0] 所表示的那段就是区间[l,r]了。 之后再进行区间的删除跟插入。
找到要插入的区间,比如插到i之后,就先把i旋转到根节点,然后然后把i的右子树中的最小的那个点旋转到根下面,这样这个最小点的左节点就是空的节点,可以插入那段区间了。
翻转的操作反而更加简单, 只用获得节点,传递一个修改的标记的就好了。
http://blog.csdn.net/acm_cxlove/article/details/7795244 原博客
代码:
//// 3487.cpp// ACM_HDU//// Created by ipqhjjybj on 13-9-6.// Copyright (c) 2013年 ipqhjjybj. All rights reserved.// 先看完别人代码。后来凭记忆敲的Ac代码//#include<iostream>#include<cstring>#include<queue>#include<cstdio>#include<algorithm>#define N 300015#define inf 1<<29#define MOD 100000007#define LL long long#define _match(a,b) ((a)==(b))#define Key_value ch[ch[root][1]][0]using namespace std;int n,q;int size[N],pre[N],key[N],num[N],rev[N];int ch[N][2],tot,root,node[N];void Push_Up(int &t){ size[t]=size[ch[t][0]]+size[ch[t][1]]+1;}void Push_Down(int &t){ if(rev[t]){ swap(ch[t][0],ch[t][1]); rev[ch[t][0]]^=1; rev[ch[t][1]]^=1; rev[t]=0; }}void NewNode(int &t,int k,int father){ t=++tot; pre[t]=father; key[t]=k; rev[t]=0; ch[t][0]=ch[t][1]=0;}void Build(int &t,int l,int r,int father){ if(l>r)return; int mid=(l+r)>>1; NewNode(t,mid,father); Build(ch[t][0],l,mid-1,t); Build(ch[t][1],mid+1,r,t); Push_Up(t);}void Init(){ root=tot=0; ch[root][0]=ch[root][1]=pre[root]=rev[root]=size[root]=0; NewNode(root,-1,0); NewNode(ch[root][1],-1,root); size[root]=2; Build(Key_value,1,n,ch[root][1]); Push_Up(ch[root][1]); Push_Up(root);}void Rotate(int x,int c){ // c==0左旋,c==1右旋 int y=pre[x]; Push_Down(y); Push_Down(x); ch[y][!c]=ch[x][c]; pre[ch[x][c]]=y; if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x]=pre[y]; ch[x][c]=y; pre[y]=x; Push_Up(y);}void Splay(int x,int father){ Push_Down(x); while(pre[x]!=father){ int y=pre[x],z=pre[y]; Push_Down(z),Push_Down(y),Push_Down(z); if(pre[y]==father){ Rotate(x,ch[y][0]==x); }else{ if(ch[z][0]==y){ if(ch[y][0]==x) Rotate(y,1),Rotate(x,1); else Rotate(x,0),Rotate(x,1); }else{ if(ch[y][0]==x) Rotate(x,1),Rotate(x,0); else Rotate(y,0),Rotate(x,0); } } } Push_Up(x); if(father==0) root=x;}int Get_Kth(int t,int k){ Push_Down(t); if(size[ch[t][0]]==k-1) return t; else if(size[ch[t][0]]>=k) return Get_Kth(ch[t][0],k); else return Get_Kth(ch[t][1],k-size[ch[t][0]]-1);}int Min_Value(int t){ Push_Down(t); while(ch[t][0]){ t=ch[t][0]; Push_Down(t); } return t;}void Reversal(int a,int b){ a=Get_Kth(root,a); b=Get_Kth(root,b+2); Splay(a,0); Splay(b,root); rev[Key_value]^=1;}void Cut(int a,int b,int c){ int x=Get_Kth(root,a); int y=Get_Kth(root,b+2); Splay(x,0); Splay(y,root); int tmp=Key_value; Key_value=0; Push_Up(ch[root][1]); Push_Up(root); int cm=Get_Kth(root,c+1); Splay(cm,0); int mi=Min_Value(ch[root][1]); Splay(mi,root); Key_value=tmp; pre[Key_value]=ch[root][1]; Push_Up(ch[root][1]); Push_Up(root);}int cnt;void InOrder(int r){ if(r==0) return; Push_Down(r); InOrder(ch[r][0]); if(cnt>=1&&cnt<=n){ if(cnt>1)printf(" "); printf("%d",key[r]); } cnt++; InOrder(ch[r][1]);}int main(){ while(scanf("%d%d",&n,&q)!=EOF){if(n==-1&&q==-1)break;Init();while(q--){char str[10];int a,b,c;scanf("%s",str);if(str[0]=='C'){scanf("%d%d%d",&a,&b,&c);Cut(a,b,c);}else{scanf("%d%d",&a,&b);Reversal(a,b);}}cnt=0;InOrder(root);printf("\n");}return 0;}
HDU 3436
这道题是离散化数据来进行Splay。 非常感谢这位大牛的代码。
很有借鉴的意义。。 区间的离散, 把需要的点单独存,end跟beg都为1,不然就保存的时候, 1到a1-1就保存成 beg=1, end=a1-1这样类似的。。
理解后就感觉不难了。
原博客:http://blog.sina.com.cn/s/blog_6c7729450100uvye.html
代码:
//// 3436.cpp// ACM_HDU//// Created by ipqhjjybj on 13-9-7.// Copyright (c) 2013年 ipqhjjybj. All rights reserved.// 先看完别人代码的。。//#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>using namespace std;const int MAXN = 222222;int n,q,k,N;char re[MAXN];int req[MAXN],a[MAXN],na,beg[MAXN],end[MAXN];int num[MAXN],pre[MAXN],ch[MAXN][2],root;void flow(int x){ num[x]=num[ch[x][0]]+num[ch[x][1]]+end[x]-beg[x]+1;}inline void rotate(int n){ int t=pre[n]; bool isr=(ch[t][1]==n); ch[t][isr]=ch[n][!isr],pre[ch[n][!isr]]=t; pre[n]=pre[t],ch[pre[t]][ch[pre[t]][1]==t]=n; pre[t]=n,ch[n][!isr]=t; flow(t);}inline void splay(int n,int goal){ int f,ff; while(pre[n]!=goal) { f=pre[n],ff=pre[f]; if(goal==ff) rotate(n); else if((ch[ff][1]==f)==(ch[f][1]==n)) rotate(f),rotate(n); else rotate(n),rotate(n); } flow(n); if(!goal) root=n;}void Top(int t){ splay(t,0); int x=ch[t][1]; while(ch[x][0]) x=ch[x][0]; splay(x,t); ch[x][0]=ch[t][0],pre[ch[t][0]]=x; ch[t][0]=0; //因为算法的特殊性.root不能变为t; flow(t);}int Rank(int n){ int t=root; while(1){ if(num[ch[t][0]]<n&&num[ch[t][0]]+end[t]-beg[t]+1>=n) break; if(n<=num[ch[t][0]]) t=ch[t][0]; else { n-=num[ch[t][0]]+end[t]-beg[t]+1,t=ch[t][1]; } } int ans=beg[t]+n-1-num[ch[t][0]]; splay(t,0); return ans;}int Query(int x){ splay(x,0); return num[ch[x][0]]+1;}int Bisearch(int n){ int l=1,r=N,mid; while(l<=r) { mid=(l+r)>>1; if(beg[mid]>n) r=mid-1; else if(end[mid]<n) l=mid+1; else return mid; } return l;}int main(){ int t,tt=0,val,i,j; char str[10]; scanf("%d",&t); while(t--){ scanf("%d %d",&n,&q); k=0; na=0; for(i=0;i<q;i++){ scanf("%s %d",str,&val); re[k]=str[0],req[k++]=val; if(str[0]=='T'){ a[na++]=val; } } sort(a,a+na); for(j=i=1;i<na;i++) if(a[i]!=a[i-1]) a[j++]=a[i]; na=j;j=1; if(a[0]>1){ beg[j]=1,end[j++]=a[0]-1; } for(i=0;i<na;i++){ end[j]=beg[j]=a[i],j++; if(i<na-1){ if(a[i]+1<a[i+1]){ beg[j]=a[i]+1,end[j]=a[i+1]-1; j++; } }else{ beg[j]=a[i]+1,end[j]=n,j++; } } beg[j]=end[j]=n+1;j++; memset(ch,0,sizeof(int)*(j+2)*2); num[0]=0,N=j-1; for(i=1;i<=N;i++){ num[i]=num[i-1]+end[i]-beg[i]+1; pre[i-1]=i,ch[i][0]=i-1; }pre[N]=0; root=N; printf("Case %d:\n",++tt); for(i=0;i<k;i++){ if(re[i]=='T'){ Top(Bisearch(req[i])); }else if(re[i]=='R'){ printf("%d\n",Rank(req[i])); }else{ j=Bisearch(req[i]); printf("%d\n",Query(j)+req[i]-beg[j]); } } } return 0;}
- 当初学 Splay树 所看过的,凭理解打过的代码
- 回忆当初写过的代码
- 记录当初面试时所遇到过的各种面试题
- 我学过的java5 理解Map
- 没学过Word排版的看过来 Word排版技巧分享
- 当初为蜂巢样式实验过的方法
- 当初为蜂巢样式实验过的方法
- 当初为蜂巢样式实验过的方法
- 取得git 打好的tag所对应的代码
- 取得git 打好的tag所对应的代码
- 有关【学过该课程的同学还学过】的一段代码
- 搜索代码所使用过的boost库函数等关键字
- 计算机网络的当初
- 当初的与现在
- 晒一晒咱splay的丑代码;
- 感人至深,splay的代码量
- 2012年读过的书和看过的电影
- 的更好的见到过发看过了几个老公
- iphone网站客户端,需要理解的http请求和响应
- matlab手记(1)
- 2013-09-09工作安排
- thinkphp 的目录结构
- libevent
- 当初学 Splay树 所看过的,凭理解打过的代码
- 开源框架Pushlet入门
- Java输出当前的日期(年月日时分秒毫秒)
- Typical layout of a Thesis/Professional Paper
- ext direct spring sse method
- trie树--详解
- jsp/html光标定位代码
- json,jsonp,ajax学习笔记
- perl字符串连接乱码的问题