zoukankan      html  css  js  c++  java
  • POJ 2886 线段树单点更新

    转载自:http://blog.csdn.net/sdj222555/article/details/6878651

    反素数拓展参照:http://blog.csdn.net/ACdreamers/article/details/25049767

    题目大意就是一群熊孩子做游戏,第一个出队的人是编号为k的人。此后出队的人就是按照前一个人手里的编号。如果是正数+m就是这个人的左边的第m个人。如果是负数-m,就是 这个人的右边第m个人。由于这个人出队了。对下一个人有影响,所以+m的时候,是k+m-1。-m的时候是k+m。因为是他后边的人所以没有影响。因为可能出现负数和0的情况,所以就有下面的取模时的处理。线段树的每个节点保存的是这个区间还有多少个位置。所以每次更新时,如果左孩子节点的空位够了,搜索左孩子,否则搜索右孩子。可以建树参照对样例模拟一下。

    还不懂怎么打反素数表。所以是cooy的。

    附代码:

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <iostream>
     4 using namespace std;
     5 
     6 #define lson l, m, rt<<1
     7 #define rson m+1, r, rt<<1|1
     8 #define N 500010
     9 
    10 int tree[N<<2];
    11 
    12 const int antiprime[] = { // 反素数表
    13     1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,
    14     1260,1680,2520,5040,7560,10080,15120,20160,25200,
    15     27720,45360,50400,55440,83160,110880,166320,221760,
    16     277200,332640,498960,554400,665280
    17 };
    18 
    19 const int factorNum[] = { // 对应的约数个数
    20     1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,
    21     64,72,80,84,90,96,100,108,120,128,144,160,168,180,
    22     192,200,216,224
    23 };
    24 
    25 struct child{  // 保存输入时的节点信息
    26     char name[15];
    27     int val;
    28 }c[N];
    29 
    30 void Build(int l, int r, int rt) {  // 建树
    31    tree[rt] = r-l+1;
    32    if (l == r)
    33    return;
    34    int m = (l+r)>>1;
    35    Build(lson);
    36    Build(rson);
    37 }
    38 
    39 int Update(int p, int l, int r, int rt) {  // 第p个人出去。Update函数可以理解。
    40     tree[rt]--;
    41     if (l == r)
    42     return r;
    43     int m = (l+r)>>1;
    44     if (p<=tree[rt<<1])
    45     return Update(p, lson);
    46     else return Update(p-tree[rt<<1], rson);
    47 }
    48 
    49 int main() {
    50    int i, n, &mod = tree[1];
    51    // mod 保存的就是一共有多少个人、
    52    int k;
    53 
    54    while(~scanf("%d%d", &n, &k)) {
    55      // 输入建树
    56      for (i=1; i<=n; ++i) {
    57         scanf("%s%d", c[i].name, &c[i].val);
    58      }
    59      Build(1, n, 1);
    60 
    61      // 小于等于n的最大的反素数。
    62      int cnt = 0;
    63      while(cnt < 35 && antiprime[cnt] <= n) {
    64         cnt++;
    65      }
    66      cnt--;
    67      // 先找到1-n范围内的约束个数最大的数。
    68 
    69      // pos是记录当前位置该出队的人的ID
    70      int pos = 0;
    71      c[pos].val = 0;
    72 
    73      // 找antiprime[cnt]出队的人的名字、
    74      for (i=0; i<antiprime[cnt]; ++i) {  // 循环的次数就是直到这个人出队。
    75 
    76         // 这两个if是根据 这个人手里牌的编号来推算下一个出队列的人的当前位置、
    77         if (c[pos].val > 0)
    78         k = ((k+c[pos].val-2)%mod+mod)%mod+1;
    79         else k=((k+c[pos].val-1)%mod+mod)%mod+1;
    80 
    81        // pos 记录的是当前循环出队的人的所在位置、
    82         pos = Update(k, 1, n, 1);
    83         cout << pos << "====
    ";
    84      }
    85      printf("%s %d
    ", c[pos].name, factorNum[cnt]);
    86    }
    87    return 0;
    88 }
    View Code
  • 相关阅读:
    oracle增加字段,循环
    mybatis批量插入和更新
    oracle触发器
    Java中<? extends T>和<? super T>的理解
    函数式编程
    mybaitis
    操作word
    服务大厅流程
    jdk动态代理
    操作系统
  • 原文地址:https://www.cnblogs.com/icode-girl/p/4853688.html
Copyright © 2011-2022 走看看