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
  • 相关阅读:
    USACO 3.3 A Game
    USACO 3.3 Camelot
    USACO 3.3 Shopping Offers
    USACO 3.3 TEXT Eulerian Tour中的Cows on Parade一点理解
    USACO 3.3 Riding the Fences
    USACO 3.2 Magic Squares
    USACO 3.2 Stringsobits
    USACO 3.2 Factorials
    USACO 3.2 Contact
    USACO 3.1 Humble Numbers
  • 原文地址:https://www.cnblogs.com/icode-girl/p/4853688.html
Copyright © 2011-2022 走看看