码迷,mamicode.com
首页 > 其他好文 > 详细

Joseph问题 (线段树)

时间:2018-10-06 00:34:28      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:return   复杂度   返回   span   owb   i++   class   目的   efi   

Joseph问题似乎是入门题,就是那个报数出圈的问题,不过它暴力模拟的复杂度是O(nm)的,如果题目的数据范围达到了30000,那就超时了。怎么用线段树维护呢?

我们可以这么考虑,每次我们其实要查询在当前这个点过了m个人是哪一个人。我们需要维护一下当前序列中一共有多少人,还需要维护每个人实际的位置在哪(因为人们出圈了之后他就不占位置了)

我们可以用一棵权值线段树来完成。

首先是修改,这个没什么好说的,直接单点修改改成0就行,然后同时返回修改的位置,这是一个人出圈的位置。不过怎么找到这个位置呢?我们可以首先确定下来这个人在当前序列的第几位,那么我们直接在线段树上二分就可以了,然后返回那个位置。

一开始我们要query一下从1到上一次停留位置有几个人,然后把这个值+m-1,mod现在所有的人数再+1就是当前位置,找一下那个人在哪就可以了。

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<set>
#define lowbit(x) x & (-x)
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar(‘\n‘)

using namespace std;
typedef long long ll;
const int M = 60005;
const ll INF = 100000000000009;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < 0 || ch > 9)
    {
        if(ch == -) op = -1;
        ch = getchar();
    }
    while(ch >= 0 && ch <= 9)
    {
        ans *= 10;
        ans += ch - 0;
        ch = getchar();
    }
    return ans * op;
}

struct seg
{
    int v;
} t[M<<2];

int n,m,last,g;

void build(int p,int l,int r)
{
    if(l == r)
    {
        t[p].v = 1;
        return;
    }
    int mid = (l+r) >> 1;
    build(p<<1,l,mid),build(p<<1|1,mid+1,r);
    t[p].v = t[p<<1].v + t[p<<1|1].v;
}

int query(int p,int l,int r,int pos)
{
    if(l == r) return t[p].v = 0,l;
    int mid = (l+r) >> 1,cur;
    if(pos <= t[p<<1].v) cur = query(p<<1,l,mid,pos);
    else cur = query(p<<1|1,mid+1,r,pos-t[p<<1].v);
    t[p].v = t[p<<1].v + t[p<<1|1].v;
    return cur;
}

int count(int p,int l,int r,int kl,int kr)
{
    if(kl > kr) return 0;
    if(l == kl && r == kr) return t[p].v;
    int mid = (l+r) >> 1;
    if(kr <= mid) return count(p<<1,l,mid,kl,kr);
    else if(kl > mid) return count(p<<1|1,mid+1,r,kl,kr);
    else return count(p<<1,l,mid,kl,mid) + count(p<<1|1,mid+1,r,mid+1,kr);
}

int main()
{
    n = read(),m = read();
    build(1,1,n);
    rep(i,1,n) printf("%d ",last = query(1,1,n,(count(1,1,n,1,last)+m-1)%t[1].v+1));
    return 0;
}

 

Joseph问题 (线段树)

标签:return   复杂度   返回   span   owb   i++   class   目的   efi   

原文地址:https://www.cnblogs.com/captain1/p/9746381.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!