xdu_1009: Josephus环的复仇(线段树)

题目链接

题意不难理解,解法具体看代码及注释吧。。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

const int maxn=2e5+7;
int n,k;
int ql,qr;
int pos; //当前要出队的人在剩余人中排在第几靠左的地方 

struct node
{
    int l,r;
    int pre;    //记录区间中剩余的最靠右的人在所有剩余人中的位置
    int lz;        //lazy标记
} a[maxn<<2];

void push_up(int rt)
{
    a[rt].pre=max(a[rt<<1].pre,a[rt<<1|1].pre);
}
void build(int rt,int l,int r)
{
    a[rt].l=l,a[rt].r=r;
    if(l==r)
    {
        a[rt].pre=l;
        return ;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    push_up(rt);
}
void update(int rt)
{
    int l=a[rt].l,r=a[rt].r;
    if(ql<=l&&r<=qr)
    {
        --a[rt].pre;
        --a[rt].lz;
        return ;
    }
    int mid=(l+r)>>1;
    if(ql<=mid) update(rt<<1);
    if(qr>mid)  update(rt<<1|1);
    push_up(rt);
}
void push_down(int rt)
{
    int& lz=a[rt].lz;
    if(lz==0) return ;
    a[rt<<1].lz+=lz;
    a[rt<<1|1].lz+=lz;
    a[rt<<1].pre+=lz;
    a[rt<<1|1].pre+=lz;
    lz=0;
}
int query(int rt)
{
    int l=a[rt].l,r=a[rt].r;
    if(l==r) return l;
    push_down(rt);
    int mid=(l+r)>>1;
    if(a[rt<<1].pre>=pos) return query(rt<<1);
    else return query(rt<<1|1);
}

int main()
{
    scanf("%d%d",&n,&k);
    build(1,1,n);
    int cnt=n;
    pos=1;
    for(int i=0;i<n;i++)
    {
        pos=(pos-2+k+cnt*2)%cnt+1;    //当前位置变更
        --cnt;    //少了个人
        int p=query(1);        //出队人在原队伍中的位置
        printf("%d%c",p,i==n-1? ‘\n‘:‘ ‘);
        ql=p,qr=n;            //出队后,pre发生变化的区间范围
        update(1);
    }
}
时间: 2024-10-12 12:23:55

xdu_1009: Josephus环的复仇(线段树)的相关文章

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

POJ 2886 Who Gets the Most Candies?(线段树&#183;约瑟夫环)

题意  n个人顺时针围成一圈玩约瑟夫游戏  每个人手上有一个数val[i]   开始第k个人出队  若val[k] < 0 下一个出队的为在剩余的人中向右数 -val[k]个人   val[k] > 0 时向左数val[k]个  第m出队的人可以得到m的约数个数个糖果  问得到最多糖果的人是谁 约瑟夫环问题  n比较大 直接模拟会超时   通过线段树可以让每次出队在O(logN)时间内完成  类似上一道插队的题  线段树维护对应区间还有多少个人没出队  那么当我们知道出队的人在剩余人中排第几个

HDU5957 Query on a graph(拓扑找环,BFS序,线段树更新,分类讨论)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5957 题意:D(u,v)是节点u和节点v之间的距离,S(u,v)是一系列满足D(u,x)<=k的点的集合,操作1:将S(u,k)内节点权值增加或者减小,操作2:查询S(u,k)内节点的权值和 题解:因为题目说了查询和更新的距离小于等于k,k最大为2,所以很显然要分情况讨论k为0.1.2的情况 因为是多次更新,我们显然是需要用线段树来维护节点权值的 运用线段树和bfs序的知识我们知道 对一个棵树求BFS

约瑟夫环小结(线段树)

题目大意: 输入初始人数编号为1~n,以及初始密码m,输出出局序列. 解法一:用线段树可解. Segtree节点存储左右区间和该区间下包含的人数. void Build(int p,int left,int right)表示从编号为p,区间为[l,r]的节点开始向下建树. int Update(int p,int id)表示从编号为p的节点开始查询在新队伍中编号为id的人出局,返回该人在最初队伍中的编号. 而temp=(temp+m-1)%seg[1].manum;语句用于求出下一个出局的人在新

POJ 2886 Who Gets the Most Candies(线段树+约瑟夫环)

题目链接:POJ 2886 Who Gets the Most Candies [题目]N个孩子顺时针坐成一个圆圈,从1~N编号,每个孩子手中有一张标有非零整数的卡片.第K个孩子先出圈,如果他手中卡片上的数字A>0,下一个出圈的是他左手边第A个孩子.A<0,下一个出圈的是他右手边第(-A)个孩子.第p个出圈的孩子会得到F(p)个糖果,F(p)为p的因子数.输出得到糖果数最多的孩子的名字及糖果数目. [思路]孩子数目很大(1~500000),于是想到要用线段树来优化,然后就是模拟出圈过程.并更新

HDU5638 / BestCoder Round #74 (div.1) 1003 Toposort 线段树+拓扑排序

Toposort 问题描述 给出nn个点mm条边的有向无环图. 要求删掉恰好kk条边使得字典序最小的拓扑序列尽可能小. 输入描述 输入包含多组数据. 第一行有一个整数TT, 表示测试数据组数. 对于每组数据: 第一行包含3个整数nn, mm和kk (1 \le n \le 100000, 0 \le k \le m \le 200000)(1≤n≤100000,0≤k≤m≤200000), 表示图中结点数目, 图中边的数目以及要删的边数. 接下来mm行, 每行包含两个整数u_iu?i?? and

Poj2886Who Gets the Most Candies?线段树

约瑟夫环用线段数搞,一脸搞不出来的样子.反素数,太神了,先打表,然后就可以 O(1)找到因子数最多的.ps:哎.这题也是看着题解撸的. #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cs

【POJ 2750】 Potted Flower(线段树套dp)

[POJ 2750] Potted Flower(线段树套dp) Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4566   Accepted: 1739 Description The little cat takes over the management of a new park. There is a large circular statue in the center of the park, surrou

poj2750--Potted Flower(线段树)

题目链接:点击打开链接 题目大意:给出n个数排成一个环.求环的最大连续子序列,不能是总序列 建一个线段树来求最大子序列假设仅仅是一个序列.那么求最大连续子序列非常easy,可是假设是一个环,那就要考虑断点的问题,由于结果可能是由左边一部分+右边一部分,这种结果用线段树没法统计到,所以须要转换一下: 求最大连续子序列 = 总和 - 最小连续子序列 那么题目就非常easy了,要统计出每一段的最大连续子序列,最小连续子序列和总和. sum[rt] = sum[rt<<1] + sum[rt<&