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

Posted 一入OI深似海

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

 

以上是关于codevs 1282 约瑟夫问题(线段树)的主要内容,如果未能解决你的问题,请参考以下文章

AC日记——约瑟夫问题 codevs 1282

codevs1282约瑟夫问题

codves1282 约瑟夫问题 链表 会 T

codevs1228 (dfs序+线段树)

POJ2886Who Gets the Most Candies?(线段树之约瑟夫)

线段树模板合集(CodeVS1080 1081 1082 4597)Pascal代码