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;}


POJ3481

题目连接: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;}