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;
        }
    }
}

时间: 2024-10-11 12:28:22

lightoj 1179(线段树)的相关文章

LightOJ 1097 - Lucky Number 线段树

http://www.lightoj.com/volume_showproblem.php?problem=1097 题意:一个自然数序列,先去掉所有偶数项,在此基础上的序列的第二项为3,则删去所有3的倍数的元素,再是7……重复操作,最后问第n项的值 思路:使用线段树构造序列,对一个数进行标记是否已被删去,和为元素个数.由于样例给出了大小,所以很容易控制空间. /** @Date : 2016-12-05-19.34 * @Author : Lweleth ([email protected])

LightOJ 1093 - Ghajini 线段树

http://www.lightoj.com/volume_showproblem.php?problem=1093 题意:给定序列,问长度为d的区间最大值和最小值得差最大是多少. 思路:可以使用线段树做,由于固定区间长度,还可以使用单调队列. /** @Date : 2016-12-06-18.39 * @Author : Lweleth ([email protected]) * @Link : https://github.com/ * @Version : */ #include<bit

LightOJ 1089 - Points in Segments (II) 线段树区间修改+离散化

http://www.lightoj.com/volume_showproblem.php?problem=1089 题意:给出许多区间,查询某个点所在的区间个数 思路:线段树,由于给出的是区间,查询的是点,考虑将其离线并离散化,普通线段树即可. /** @Date : 2016-12-17-20.49 * @Author : Lweleth ([email protected]) * @Link : https://github.com/ * @Version : */ #include<bi

LightOJ Array Queries 1082【线段树求区间最值】

1082 - Array Queries PDF (English) Statistics Forum Time Limit: 3 second(s) Memory Limit: 64 MB Given an array with N elements, indexed from 1 to N. Now you will be given some queries in the form I J, your task is to find the minimum value from index

LightOJ 1085(树状数组+离散化+DP,线段树)

All Possible Increasing Subsequences Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Appoint description: Description An increasing subsequence from a sequence A1, A2 ... An is defined by Ai1, Ai2 ... Aik, where the followi

LightOJ 1370 Bi-shoe and Phi-shoe 欧拉函数+线段树

分析:对于每个数,找到欧拉函数值大于它的,且标号最小的,预处理欧拉函数,然后按值建线段树就可以了 #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <cmath> #include <map> using namespace std; typedef long long LL; const int N = 1

LightOj 1112 Curious Robin Hood(线段树||树状数组)

Curious Robin Hood Robin Hood likes to loot rich people since he helps the poor people with this money. Instead of keeping all the money together he does another trick. He keeps n sacks where he keeps this money. The sacks are numbered from 0 to n-1.

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间