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 约瑟夫问题(线段树)的主要内容,如果未能解决你的问题,请参考以下文章