SBT的几个题
来源:互联网 发布:2016linux运维面试题 编辑:程序博客网 时间:2024/06/14 01:53
HDU4006
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4006
题意:查找在某些数据中的第k大数
虽然可以有很多种方法来做,但是作为SBT来练手还是一个很不错的题目!这里面只有SBT的旋转,维护,插入,选择这四种基本操作,不涉及到删除和后继前驱这些操作,水题
#include<iostream>#include<cstring>#include<algorithm>#include<cstdio>#include<cmath>#include<climits>using namespace std;const int maxn=1000005;int l[maxn],r[maxn],s[maxn],k[maxn];int node;int root;//左旋转处理void left_rotate(int &t){ int k=r[t]; r[t]=l[k]; l[k]=t; s[k]=s[t]; s[t]=s[l[t]]+s[r[t]]+1; t=k;}void right_rotate(int &t){ int k=l[t]; l[t]=r[k]; r[k]=t; s[k]=s[t]; s[t]=s[l[t]]+s[r[t]]+1; t=k;}void maintain(int &t,bool flag){ if(flag==false) { if(s[l[l[t]]]>s[r[t]]) right_rotate(t); else if(s[r[l[t]]]>s[r[t]]) { left_rotate(l[t]); right_rotate(t); } else return; } else { if(s[r[r[t]]]>s[l[t]]) left_rotate(t); else if(s[l[r[t]]]>s[l[t]]) { right_rotate(r[t]); left_rotate(t); } else return ; } maintain(l[t],false); maintain(r[t],true); maintain(t,false); maintain(t,true);}void insert(int &t,int v)//插入新节点{ if(!t) { s[t=++node]=1; l[t]=r[t]=0; k[t]=v; } else { ++s[t]; if(v<k[t]) insert(l[t],v); else insert(r[t],v); maintain(t,v>=k[t]); }}//取得第K大的数int select(int &t,int kk){ int v=s[l[t]]+1; if(v==kk) return k[t]; if(kk>v) return select(r[t],kk-v); else return select(l[t],kk);}int main(){ freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin); int t,q; char a[2]; int key; while(scanf("%d%d",&t,&q)!=EOF) { node=root=s[0]=0; while(t--) { scanf("%s",a); if(a[0]=='I') { scanf("%d",&key); insert(root,key); } else { printf("%d\n",select(root,s[root]+1-q)); } } } return 0;}
题目连接:http://poj.org/problem?id=3481
题意:对于一些操作 ;当输入的C==1时表示将优先级为P的数据编号K加入到队列中;当 C == 2时表示输出队列中权值最大的编号K,并出队;当 C==3时表示输出队列中权值最小的编号K,并出队。当没得数据时输出0
#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>using namespace std;const int maxn=1000002;int lson[maxn],rson[maxn],size[maxn],v[maxn],key[maxn];int node;int root;void left_rotate(int &x){ int k=rson[x]; rson[x]=lson[k]; lson[k]=x; size[k]=size[x]; size[x]=size[lson[x]]+size[rson[x]]+1; x=k;}void right_rotate(int &y){ int k=lson[y]; lson[y]=rson[k]; rson[k]=y; size[k]=size[y]; size[y]=size[rson[y]]+size[lson[y]]+1; y=k;}void maintain(int &t,bool flag){ if(flag==false) { if(size[lson[lson[t]]]>size[rson[t]]) right_rotate(t); else if(size[rson[lson[t]]]>size[rson[t]]) { left_rotate(lson[t]); right_rotate(t); } else return; } else { if(size[rson[rson[t]]]>size[lson[t]]) left_rotate(t); else if(size[lson[rson[t]]]>size[lson[t]]) { right_rotate(rson[t]); left_rotate(t); } else return; } maintain(lson[t],false); maintain(rson[t],true); maintain(t,false); maintain(t,true);}void insert(int &t,int V,int k){ if(!t) { size[t=++node]=1; v[t]=V; key[t]=k; lson[t]=rson[t]=0; } else { ++size[t]; if(v[t]>V) insert(lson[t],V,k); else insert(rson[t],V,k); maintain(t,V>=v[t]); }}int rank(int t,int vv){ if(!t) return 1; if(v[t]>=vv) return rank(lson[t],vv); else return size[lson[t]]+rank(rson[t],vv)+1;}int maxnum(){ int t=root; int p=root; while(rson[t]) { p=t; t=rson[t]; } if(t!=p)rson[p]=lson[t]; else root=lson[t]; return key[t];}int minnum(){ int t=root; int p=root; while(lson[t]) { p=t; t=lson[t]; } if(t!=p)lson[p]=rson[t]; else root=rson[t]; return key[t];}int select(int t,int k){ int vv=size[lson[t]]+1; if(k==vv) return key[t]; else if(k<vv) return select(lson[t],k); else return select(rson[t],k-vv);}int main(){ //freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin); int sum=0; int x,y,z; root=0; size[0]=0; node=0; while(scanf("%d",&x)==1) { if(x==0)break; else if(x==1) { scanf("%d%d",&y,&z); insert(root,z,y); ++sum; } else if(sum) { if(x==2) printf("%d\n",maxnum()); if(x==3) printf("%d\n",minnum()); --sum; } else printf("0\n"); } return 0;}
POJ2892
题目连接:http://poj.org/problem?id=2892
题意:给出直线上一系列的村庄,如果相邻村庄都没有被破坏,则两村庄是连接的,题目给出一系列的破坏操作,
对指定号码的村庄进行破坏,还有一系列的询问操作,询问与指定号码的村庄直接相连或间接相连的村庄有几个,
还有一个修复操作,是对最后破坏的村庄进行修复。
思路:我们可以通过SBT来实现这些操作,通过平衡树储存已经删除了的结点。
然后查询个数可以用平衡树找到比我大一点点的那个村庄和小一点点的那个村庄。
破坏的话就是插入了。
修复的话就是删除。
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;const int maxn=50005;int l[maxn],r[maxn],s[maxn],k[maxn];int num[maxn];/****n为存储毁掉的点*****/int mm[maxn];int node;int n;int min(int a,int b){ return a<b?a:b;}int max(int a,int b){ return a>b?a:b;}void left_rotate(int &x){ int k=r[x]; r[x]=l[k]; l[k]=x; s[k]=s[x]; s[x]=s[l[x]]+s[r[x]]+1; x=k;}void right_rotate(int &x){ int k=l[x]; l[x]=r[k]; r[k]=x; s[k]=s[x]; s[x]=s[l[x]]+s[r[x]]+1; x=k;}void maintain(int &t,bool flag){ if(flag==false) { if(s[l[l[t]]]>s[r[t]]) right_rotate(t); else if(s[l[r[t]]]>s[r[t]]) { left_rotate(t); right_rotate(t); } else return ; } else { if(s[r[r[t]]]>s[l[t]]) left_rotate(t); else if(s[r[l[t]]]>s[l[t]]) { right_rotate(t); left_rotate(t); } else return ; } maintain(l[t],false); maintain(r[t],true); maintain(t,false); maintain(t,true);}void insert(int &t,int v){ if(!t) { s[t=++node]=1; k[t]=v; l[t]=r[t]=0; } else { ++s[t]; if(v<k[t]) insert(l[t],v); else insert(r[t],v); maintain(t,v>=k[t]); }}int sdelete(int &t,int v){ --s[t]; if(k[t]==v||(!l[t]&&v<k[t])||(!r[t]&&v>=k[t])) { int rr=k[t]; if(!l[t]||!r[t]) t=l[t]+r[t]; else k[t]=sdelete(l[t],k[t]+1); return rr; } else { if(v<k[t]) return sdelete(l[t],v); else return sdelete(r[t],v); }}int lessmax(int t,int kk){ if(!t)return 0; else if(kk<k[t])return lessmax(l[t],kk); else return max(k[t],lessmax(r[t],kk));}int greatmin(int t,int kk){ if(!t)return n+1; else if(k[t]<kk)return greatmin(r[t],kk); else return min(k[t],greatmin(l[t],kk));}int main(){ //freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin); int m; int a; int root=0; char ch[2]; int x=0; node=s[0]=0; while(scanf("%d%d",&n,&m)==2) { memset(num,0,sizeof(num)); memset(mm,0,sizeof(mm)); while(m--) { scanf("%s",ch); if(ch[0]=='D') { scanf("%d",&a); num[++x]=a; insert(root,a); mm[a]++;//a位置毁 } else if(ch[0]=='Q') { scanf("%d",&a); if(mm[a]) printf("0\n"); else { int ll=lessmax(root,a); int rr=greatmin(root,a); printf("%d\n",rr-ll-1); } } else if(ch[0]=='R') { sdelete(root,num[x]); mm[num[x--]]--; } } } return 0;}
ZOJ3612
题目连接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3612
题意:维护一个集合,操作有插入和删除,每一次操作结束后,输出中位数,这个题目只要是中位数的求解比较关键,其实还是SBT基本操作的应用,通过select函数的作用来求解
#include<iostream>#include<cstring>#include<algorithm>#include<cstdio>#include<cmath>#include<climits>using namespace std;const int maxn=10005;int l[maxn],r[maxn],s[maxn];long long k[maxn];char str[10];int node;int root;//左旋转处理void left_rotate(int &t){ int k=r[t]; r[t]=l[k]; l[k]=t; s[k]=s[t]; s[t]=s[l[t]]+s[r[t]]+1; t=k;}void right_rotate(int &t){ int k=l[t]; l[t]=r[k]; r[k]=t; s[k]=s[t]; s[t]=s[l[t]]+s[r[t]]+1; t=k;}void maintain(int &t,bool flag){ if(flag==false) { if(s[l[l[t]]]>s[r[t]]) right_rotate(t); else if(s[r[l[t]]]>s[r[t]]) { left_rotate(l[t]); right_rotate(t); } else return; } else { if(s[r[r[t]]]>s[l[t]]) left_rotate(t); else if(s[l[r[t]]]>s[l[t]]) { right_rotate(r[t]); left_rotate(t); } else return ; } maintain(l[t],false); maintain(r[t],true); maintain(t,false); maintain(t,true);}//插入新节点void insert(int &t,long long v){ if(!t) { s[t=++node]=1; l[t]=r[t]=0; k[t]=v; } else { ++s[t]; if(v<k[t]) insert(l[t],v); else insert(r[t],v); maintain(t,v>=k[t]); }}//删除结点,利用的是前驱替换long long sdelete(int &t,long long v){ --s[t]; if(v==k[t]||(!l[t]&&v<k[t])||(!r[t]&&v>k[t])) { long long rr=k[t]; if(!l[t]||!r[t]) t=l[t]+r[t]; else k[t]=sdelete(l[t],v+1); return rr; } else { if(v<k[t]) return sdelete(l[t],v); else return sdelete(r[t],v); }}//取得第K大的数long long select(int t,long long kk){ int v=s[l[t]]+1; if(v==kk) return k[t]; if(kk>v) return select(r[t],kk-v); else return select(l[t],kk);}//查找树中是否存在元素int search(int t,long long kk){ if(!t)return 0; if(k[t]==kk)return k[t]; else if(kk<k[t]) return search(l[t],kk); else return search(r[t],kk);}int main(){ freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin); int t,q; scanf("%d",&t); while(t--) { scanf("%d",&q); node=root=0; int cnt=0; long long key; char str[10]; while(q--) { scanf("%s%lld",str,&key); if(str[0]=='a') { insert(root,key); cnt++; if(cnt&1) printf("%lld\n",select(root,cnt/2+1)); else { long long ans=(long long)select(root,cnt/2)+(long long)select(root,cnt/2+1); if(ans&1)printf("%.1f\n",ans/2.0); else printf("%lld\n",ans/2); } } else { if(!search(root,key)) { printf("Wrong!\n"); continue; } cnt--; sdelete(root,key); if(cnt==0) { printf("Empty!\n"); continue; } if(cnt&1) printf("%lld\n",select(root,cnt/2+1)); else { long long ans=(long long)select(root,cnt/2)+(long long)select(root,cnt/2+1); if(ans&1)printf("%.1f\n",ans/2.0); else printf("%lld\n",ans/2); } } } } return 0;}
poj3517
题目连接:http://poj.org/problem?id=3517
题意:给定n个点,输入n,k,m,m表示第一次删除的点,k表示从第一次删除后下一次删除的点距离上一次删除点的距离,n,k,m都为0时表示结束,只到只剩下一个人时就输出这个人的标号,标号从1到n。这是典型的约瑟夫问题,用SBT来模拟它的过程,第一次删除m,以后下一个删除的点就是m+k-1,在判断这个店是否超过了size[root]就可以了,超过了就取余,当他是size[root]的整数倍时,就让他等于size[root]就可以了,相当于又从头开始
#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<ctime>#include<cstdlib>#include<cstring>#include<climits>#define maxn 100005using namespace std;int lson[maxn],rson[maxn];int size[maxn],key[maxn];int node,root;void right_rotate(int &t){ int k=lson[t]; lson[t]=rson[k]; rson[k]=t; size[k]=size[t]; size[t]=size[lson[t]]+size[rson[t]]+1; t=k;}void left_rotate(int &t){ int k=rson[t]; rson[t]=lson[k]; lson[k]=t; size[k]=size[t]; size[t]=size[lson[t]]+size[rson[t]]+1; t=k;}void maintain(int &t,bool flag){ if(flag==false) { if(size[lson[lson[t]]]>size[rson[t]]) right_rotate(t); else { if(size[rson[lson[t]]]>size[rson[t]]) { left_rotate(lson[t]); right_rotate(t); } else return; } } else { if(size[rson[rson[t]]]>size[lson[t]]) { left_rotate(t); } else { if(size[lson[rson[t]]]>size[lson[t]]) { right_rotate(rson[t]); left_rotate(t); } else return; } } maintain(t,false); maintain(t,true); maintain(lson[t],false); maintain(rson[t],true);}void insert(int &t,int v){ if(!t) { key[t=++node]=v; lson[t]=rson[t]=0; size[t]=1; } else { size[t]++; if(v>key[t])insert(rson[t],v); else insert(rson[t],v); maintain(t,v>=key[t]); }}int sdelete(int &t,int v){ size[t]--; if(key[t]==v||(v<key[t]&&!lson[t])||(v>key[t]&&!rson[t])) { int r=key[t]; if(!lson[t]||!rson[t]) t=lson[t]+rson[t]; else key[t]=sdelete(lson[t],key[t]+1); return r; } else if(v>key[t])return sdelete(rson[t],v); else return sdelete(lson[t],v);}int select(int t,int k){ int r=size[lson[t]]+1; if(k==r)return key[t]; else if(k<r)return select(lson[t],k); else return select(rson[t],k-r);}int main(){ int m,n,k; int ans; while(cin>>n>>k>>m,n+m+k) { root=node=size[0]=0; for(int i=1; i<=n; i++) { insert(root,i); } while(size[root]>1) { //ans=select(root,m); sdelete(root,select(root,m)); //sdelete(root,ans); m=m+k-1; if(m%size[root]==0)m=size[root]; else m=m%size[root]; } cout<<select(root,1)<<endl; } return 0;}
poj3750
题目连接:http://poj.org/problem?id=3750
题意:约瑟夫问题--依次输出出环顺序时所对应的的人的名字
#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<ctime>#include<map>#include<cstdlib>#include<cstring>#include<climits>#define maxn 100005using namespace std;int lson[maxn],rson[maxn];int size[maxn],key[maxn];char name[70][20];int node,root;void right_rotate(int &t){ int k=lson[t]; lson[t]=rson[k]; rson[k]=t; size[k]=size[t]; size[t]=size[lson[t]]+size[rson[t]]+1; t=k;}void left_rotate(int &t){ int k=rson[t]; rson[t]=lson[k]; lson[k]=t; size[k]=size[t]; size[t]=size[lson[t]]+size[rson[t]]+1; t=k;}void maintain(int &t,bool flag){ if(flag==false) { if(size[lson[lson[t]]]>size[rson[t]]) right_rotate(t); else { if(size[rson[lson[t]]]>size[rson[t]]) { left_rotate(lson[t]); right_rotate(t); } else return; } } else { if(size[rson[rson[t]]]>size[lson[t]]) { left_rotate(t); } else { if(size[lson[rson[t]]]>size[lson[t]]) { right_rotate(rson[t]); left_rotate(t); } else return; } } maintain(t,false); maintain(t,true); maintain(lson[t],false); maintain(rson[t],true);}void insert(int &t,int v){ if(!t) { key[t=++node]=v; lson[t]=rson[t]=0; size[t]=1; } else { size[t]++; if(v>key[t])insert(rson[t],v); else insert(rson[t],v); maintain(t,v>=key[t]); }}int sdelete(int &t,int v){ size[t]--; if(key[t]==v||(v<key[t]&&!lson[t])||(v>key[t]&&!rson[t])) { int r=key[t]; if(!lson[t]||!rson[t]) t=lson[t]+rson[t]; else key[t]=sdelete(lson[t],key[t]+1); return r; } else if(v>key[t])return sdelete(rson[t],v); else return sdelete(lson[t],v);}int select(int t,int k){ int r=size[lson[t]]+1; if(k==r)return key[t]; else if(k<r)return select(lson[t],k); else return select(rson[t],k-r);}int main(){ int m,n,k; int ans; while(cin>>n) { root=node=size[0]=0; for(int i=1; i<=n; i++) { insert(root,i); scanf("%s",name[i]); } scanf("%d,%d",&m,&k); while(size[root]) { m=(m+k-1); if(m%size[root]==0)m=size[root]; else m=m%size[root]; cout<<name[select(root,m)]<<endl; sdelete(root,m); } } return 0;}
Ural1521
题目连接:http://acm.timus.ru/problem.aspx?space=1&num=1521
题意:同上一题差不多
#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<ctime>#include<map>#include<cstdlib>#include<cstring>#include<climits>#define maxn 100005using namespace std;int lson[maxn],rson[maxn];int size[maxn],key[maxn];int node,root;void right_rotate(int &t){ int k=lson[t]; lson[t]=rson[k]; rson[k]=t; size[k]=size[t]; size[t]=size[lson[t]]+size[rson[t]]+1; t=k;}void left_rotate(int &t){ int k=rson[t]; rson[t]=lson[k]; lson[k]=t; size[k]=size[t]; size[t]=size[lson[t]]+size[rson[t]]+1; t=k;}void maintain(int &t,bool flag){ if(flag==false) { if(size[lson[lson[t]]]>size[rson[t]]) right_rotate(t); else { if(size[rson[lson[t]]]>size[rson[t]]) { left_rotate(lson[t]); right_rotate(t); } else return; } } else { if(size[rson[rson[t]]]>size[lson[t]]) { left_rotate(t); } else { if(size[lson[rson[t]]]>size[lson[t]]) { right_rotate(rson[t]); left_rotate(t); } else return; } } maintain(t,false); maintain(t,true); maintain(lson[t],false); maintain(rson[t],true);}void insert(int &t,int v){ if(!t) { key[t=++node]=v; lson[t]=rson[t]=0; size[t]=1; } else { size[t]++; if(v>key[t])insert(rson[t],v); else insert(rson[t],v); maintain(t,v>=key[t]); }}int sdelete(int &t,int v){ size[t]--; if(key[t]==v||(v<key[t]&&!lson[t])||(v>key[t]&&!rson[t])) { int r=key[t]; if(!lson[t]||!rson[t]) t=lson[t]+rson[t]; else key[t]=sdelete(lson[t],key[t]+1); return r; } else if(v>key[t])return sdelete(rson[t],v); else return sdelete(lson[t],v);}int select(int t,int k){ int r=size[lson[t]]+1; if(k==r)return key[t]; else if(k<r)return select(lson[t],k); else return select(rson[t],k-r);}int main(){ int m,n,k; int ans; while(cin>>n) { root=node=size[0]=0; for(int i=1; i<=n; i++) { insert(root,i); } scanf("%d",&k); m=k; cout<<select(root,m)<<endl; sdelete(root,select(root,m)); while(size[root]) { m=(m+k-1); if(m%size[root]==0)m=size[root]; else m=m%size[root]; cout<<select(root,m)<<endl; sdelete(root,select(root,m)); } } return 0;}
- SBT的几个题
- sbt的安装配置
- sbt的源配置
- SBT的构建配置
- SBT
- SBT
- SBT!!
- SBT
- SBT
- SBT
- sbt
- SBT
- [NOI2004]郁闷的出纳员 SBT
- 基于SBT的学生成绩管理系统
- Idea运行SBT的修改
- sbt打包WordCount的过程
- POJ 3481 SBT基础题
- NOI2004 郁闷的出纳员(SBT的应用)
- day7 test02
- Tab系列
- Arduino笔记三气压模块BMP85
- 客户端分页处理器
- C++实践忠告
- SBT的几个题
- build-essential软件包
- 链接、装载、库
- 读书笔记
- 详解python实现FP-TREE进行关联规则挖掘(带有FP树显示功能)附源代码下载(4)
- JExcelAPI读写EXCEL
- 学习C++ -> 向量(vector)
- 交叉编译
- Martin Fowler厌倦ORM了