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 << "====\n";
84      }
85      printf("%s %d\n", c[pos].name, factorNum[cnt]);
86    }
87    return 0;
88 }

时间: 2024-10-03 14:55:33

POJ 2886 线段树单点更新的相关文章

poj 2886 线段树的更新+反素数

Who Gets the Most Candies? Time Limit: 5000 MS Memory Limit: 0 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description N children are sitting in a circle to play a game. The children are numbered from

poj 2828(线段树单点更新)

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 18561   Accepted: 9209 Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue… The Lunar New Year wa

POJ 2828 (线段树 单点更新) Buy Tickets

倒着插,倒着插,这道题是倒着插! 想一下如果 Posi 里面有若干个0,那么排在最前面的一定是最后一个0. 从后往前看,对于第i个数,就应该插在第Posi + 1个空位上,所以用线段树来维护区间空位的个数. 说一下那个坑爹的第56行的判断: if(i > 1) printf(" "); 将输出的n个数用空格隔开,我感觉这是一个还算常用的写法啊,结果各种莫名TLE,加上输入挂也补救不回来. 去掉这个无谓的判断后,3594MS险过,加上输入挂3094MS,还算是起到了一定的加速作用.

POJ 2828 线段树单点更新 离线搞

Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue- The Lunar New Year was approaching, but unluckily the Little Cat still had schedules going here and there. Now, he ha

POJ训练计划2828_Buy Tickets(线段树/单点更新)

解题报告 题意: 插队完的顺序. 思路: 倒着处理数据,第i个人占据第j=pos[i]+1个的空位. 线段树维护区间空位信息. #include <iostream> #include <cstdio> #include <cstring> using namespace std; struct node { int x,v; } num[201000]; int sum[1000000],ans[201000]; void cbtree(int rt,int l,in

POJ训练计划2299_Ultra-QuickSort(线段树/单点更新)

解题报告 题意: 求逆序数. 思路: 线段树离散化处理. #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define LL long long using namespace std; LL sum[2001000],num[501000],_hash[501000]; void push_up(int rt) { sum[rt]=sum[rt*2

POJ 1804 Brainman(5种解法,好题,【暴力】,【归并排序】,【线段树单点更新】,【树状数组】,【平衡树】)

Brainman Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 10575   Accepted: 5489 Description BackgroundRaymond Babbitt drives his brother Charlie mad. Recently Raymond counted 246 toothpicks spilled all over the floor in an instant just b

POJ 2828 Buy Tickets (线段树 单点更新 变形)

题目链接 题意:有N个人排队,给出各个人想插队的位置和标识,要求输出最后的序列. 分析:因为之前的序列会因为插队而变化,如果直接算时间复杂度很高,所以可以用 线段树逆序插入,把序列都插到最后一层,len记录该区间里还剩余多少位置,插入的时候就插到剩余的第几个位置, 比如1,2已经插入了,如果再想插入第3个位置,则实际上插入的是5. 因为是逆序的,所以在3之前除了现在的1,2 还有之前的1,2. 1 #include <iostream> 2 #include <cstdio> 3

Buy Tickets+POJ+线段树单点更新的灵活运用

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 12927   Accepted: 6410 Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue- The Lunar New Year wa