lightoj 1179(线段树)

 

传送门:Josephus Problem

题意:经典约瑟夫问题,有n个人,每次数到第k个人出列,求剩下的最后一人。

分析:用线段树模拟约瑟夫问题,记录区间的减少情况,然后根据每次数到的人在区间排第几位,线段树log(n)找到并更新,总复杂度为O(nlog(n))。

#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>

#define N 100010

#define mod 1000000007

#define LL long long

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

using namespace std;

int n,k;

int sum[N<<2],vis[N];

void Pushup(int rt)

{

    int ls=rt<<1,rs=ls|1;

    sum[rt]=sum[ls]+sum[rs];

}

void build(int l,int r,int rt)

{

    if(l==r)

    {

        sum[rt]=1;return;

    }

    int m=(l+r)>>1;

    build(lson);

    build(rson);

    Pushup(rt);

}

void update(int num,int l,int r,int rt)

{

    if(l==r)

    {

        vis[l]=1;

        sum[rt]=0;

        return;

    }

    int m=(l+r)>>1;

    if(num<=sum[rt<<1])update(num,lson);

    else update(num-sum[rt<<1],rson);

    Pushup(rt);

}

int main()

{

    int T,cas=1;

    scanf("%d",&T);

    while(T--)

    {

        scanf("%d%d",&n,&k);

        memset(vis,0,sizeof(vis));

        build(1,n,1);

        int num=1;

        for(int i=n;i>1;i--)

        {

            num=(num+k-1)%i;

            if(num==0)num=i;

            update(num,1,n,1);

        }

        for(int i=1;i<=n;i++)

        if(!vis[i])

        {

            printf("Case %d: %d\n",cas++,i);break;

        }

    }

}
View Code

 

你可能感兴趣的:(线段树)