• codevs 1282 约瑟夫问题(线段树)


    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 30010
    using namespace std;
    int n,m,num;
    struct node
    {
        int l,r,lc,rc,sum,fa;//sum是还有几个没出队的 
    }t[maxn*2+1000];
    void Build(int ll,int rr)
    {
        int k=++num;
        t[k].l=ll;t[k].r=rr;
        if(ll!=rr-1)
          {
              t[k].lc=num+1;t[t[k].lc].fa=k;
              Build(ll,(ll+rr)/2);
              t[k].rc=num+1;t[t[k].rc].fa=k;
              Build((ll+rr)/2,rr);
              t[k].sum=t[t[k].lc].sum+t[t[k].rc].sum;
          }
        else t[k].sum=1;
    }
    int Printf(int k,int x)
    {
        while(t[k].sum<x)x-=t[k].sum;
        //要出队的标号可能大于剩下的人数 所以减到还有的范围内 不能%  
        while(t[k].l!=t[k].r-1)
          {
              if(t[t[k].lc].sum<x)
                {
                    x=x-t[t[k].lc].sum;
                    k=t[k].rc;
              }
            else k=t[k].lc;
          }
        printf("%d ",t[k].l);
        for(int i=k;i>=1;i=t[i].fa)t[i].sum--;//更新父亲们的sum 
        return t[k].l;
    }
    int find(int k,int ll,int rr)
    {
        if(ll<=t[k].l&&rr>=t[k].r)return t[k].sum;
        int ans=0;
        int mid=(t[k].l+t[k].r)/2;
        if(ll<mid)ans+=find(t[k].lc,ll,rr);
        if(rr>mid)ans+=find(t[k].rc,ll,rr);
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        Build(1,1+n);
        int p=m,k;
        for(int i=1;i<=n;i++)
          {
              k=Printf(1,p);//这次出队的是几号 
              k=find(1,1,k+1);//这次出队的号码之前还有几个没出队的 
              p=k+m;//下一个出队的是几号 
          }
        return 0;
    }
  • 相关阅读:
    SpringBoot入门
    VUE 监听局部滚动 设置ICON的位置跟随
    手机端页面调试工具-vconsole使用
    js获取字符串字节的位数
    判断数据为[] {} /空数组或空对象
    Vue axios 上传图片
    Vue触发input选取文件点击事件
    腾讯地图添加多个Marker
    VUE-CLI 设置页面title
    小程序wxml文件引用方式
  • 原文地址:https://www.cnblogs.com/yanlifneg/p/5500567.html
Copyright © 2020-2023  润新知