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;
}
时间: 2024-11-07 09:55:00

codevs 1282 约瑟夫问题(线段树)的相关文章

wikioi 1282 约瑟夫问题 线段树

和上一题一样,寻找第K个位置,只不过需要处理一下下一个位置在哪,画图看看就知道了. #include <cstdio> #include <algorithm> #include <iostream> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int maxn = 30000+5; int sum[max

[Codevs] 1282 约瑟夫问题

1282 约瑟夫问题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 有编号从1到N的N个小朋友在玩一种出圈的游戏.开始时N个小朋友围成一圈,编号为I+1的小朋友站在编号为I小朋友左边.编号为1的小朋友站在编号为N的小朋友左边.首先编号为1的小朋友开始报数,接着站在左边的小朋友顺序报数,直到数到某个数字M时就出圈.直到只剩下1个小朋友,则游戏完毕. 现在给定N,M,求N个小朋友的出圈顺序. 输入描述 Input Descri

codevs 1299 切水果 线段树

1299 切水果 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description 简单的说,一共N个水果排成一排,切M次,每次切[L,R]区间的所有水果(可能有的水果被重复切),每切完一次输出剩下水果数量 数据已重新装配,不会出现OLE错误 时限和数据范围适当修改,避免数据包过大而浪费空间资源 输入描述 Input Description 第1行共包括2个正整数,分别为N,M. 接下来m行每行两个正整数L,R 输出描述 Output Description 一共输出M行,每

codevs 2216 行星序列 线段树+延迟标记(BZOJ 1798)

2216 行星序列 时间限制: 2 s 空间限制: 256000 KB 题目描述 Description “神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始,他就报名参加了“小小宇航员夏令营”,在这里小可可不仅学到了丰富的宇航知识,还参与解决了一些模拟飞行中发现的问题,今天指导老师交给他一个任务,在这次模拟飞行的路线上有N个行星,暂且称它们为一个行星序列,并将他们从1至n标号,在宇宙未知力量的作用下这N个行星的质量是不断变化的,所以他们对飞船产生的引力也会不断变化,

线段树1

线段树的基本操作 1.特点:与普通的树不同,线段树存取的是某一个区间,它在各个节点保存一条线段. 2.节点储存方式:(结构体) 方式一:数组储存 struct Tree { int leftnode, rightnode; //区间的最左端和最右端 long long sum; //该节点储存区间的值 } tree[N *4]; //比常规储存的数组要大四倍(Be careful!) 方式二:链表储存(自己了解) struct Tree { int Left, Right; Tree *Left

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

1282 约瑟夫问题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题解 查看运行结果 题目描述 Description 有编号从1到N的N个小朋友在玩一种出圈的游戏.开始时N个小朋友围成一圈,编号为I+1的小朋友站在编号为I小朋友左边.编号为1的小朋友站在编号为N的小朋友左边.首先编号为1的小朋友开始报数,接着站在左边的小朋友顺序报数,直到数到某个数字M时就出圈.直到只剩下1个小朋友,则游戏完毕. 现在给定N,M,求N个小朋友的出圈顺序. 输入描述 In

poj 2886 Who Gets the Most Candies?(线段树+约瑟夫环+反素数)

Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 9934   Accepted: 3050 Case Time Limit: 2000MS Description N children are sitting in a circle to play a game. The children are numbered from 1 to N in clockwise o

[Codevs] 1080 线段树练习

1080 线段树练习 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 一行N个方格,开始每个格子里都有一个整数.现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和:修改的规则是指定某一个格子x,加上或者减去一个特定的值A.现在要求你能对每个提问作出正确的回答.1≤N<100000,,提问和修改的总数m<10000条. 输入描述 Input Description 输入文件第一行为一个整

【树状数组区间修改区间求和】codevs 1082 线段树练习 3

http://codevs.cn/problem/1082/ [AC] 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=2e5+2; 5 int n; 6 ll a[maxn]; 7 ll c1[maxn]; 8 ll c2[maxn]; 9 int lowbit(int x) 10 { 11 return x&-x; 12 } 13 void add(l