• hdu 5239 Doom(线段树)


    Doom

    Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
    Total Submission(s): 1401    Accepted Submission(s): 368


    Problem Description
    THE END IS COMINGGGGGG!

    Mike has got stuck on a mystery machine. If he cannot solve this problem, he will go to his doom.

    This machine is consist of n cells, and a screen. The i-th cell contains a number ai(1in). The screen also contains a number s, which is initially 0.

    There is a button on each cell. When the i-th is pushed, Mike observes that, the number on the screen will be changed to s+ai, where s is the original number. and the number on the i-th cell will be changed to a2i.

    Mike observes that the number is stored in radix p, where p=9223372034707292160. In other words  , the operation is under modulo p

    And now, Mike has got a list of operations. One operation is to push buttons between from l-th to r-th (both included), and record the number on the screen. He is tired of this stupid work, so he asks for your help. Can you tell him, what are the numbers recorded.

     
    Input
    The first line contains an integer T(T5), denoting the number of test cases.

    For each test case, the first line contains two integers n,m(1n,m105).

    The next line contains n integers ai(0ai<p), which means the initial values of the n cells.

    The next m lines describe operations. In each line, there are two integers l,r(1lrn), representing the operation.

     
    Output
    For each test case, output ''Case #t:'', to represent this is the t-th case. And then output the answer for each query operation, one answer in a line.

    For more details you can take a look at the example.
     
    Sample Input
    2 4 4 2 3 4 5 1 2 2 3 3 4 1 4 1 3 2 1 1 1 1 1 1
     
    Sample Output
    Case #1: 5 18 39 405 Case #2: 2 6 22
     
    Source
     
     
    给出n个数和一个初始值为0的答案。每次操作给出一个区间[l,r],把区间所有的数加到答案中,
    之后把区间的每个数都平方。每次操作都需要输出答案 mod 9223372034707292160(2 ^ 63 - 2 ^ 31)
    思路,
    求区间和,容易想到线段树,但是这个题要把区间中的数平方取模,好像没法维护区间和。
    但是关键是任意数的平方对题目中的mod取模,重复操作至多29次就会进入一个不变的数。
    怎么知道最后会不变的...坑爹
      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define L(root) ((root) << 1)
      5 #define R(root) (((root) << 1) | 1)
      6 
      7 #define LL long long
      8 #define ULL unsigned long long
      9 //const long long mod=((1ll<<63)-(1ll<<31));//这是个什么数
     10 
     11 const ULL MOD = 9223372034707292160ULL;
     12 
     13 //乘法转加法
     14 ULL squareMod(ULL a)
     15 {
     16     ULL b = a;
     17     ULL sum = 0;
     18     while (b) {
     19         if (b & 1) {
     20             sum = (sum + a) % MOD;
     21         }
     22         a = (a + a) % MOD;
     23         b >>= 1;
     24     }
     25     return sum;
     26 }
     27 
     28 const int MAXN = 1e5 + 5;
     29 ULL numbers[MAXN];
     30 
     31 struct Node {
     32     int left, right;
     33     ULL sum;
     34     bool same;//
     35     //int cnt;//
     36     int mid()
     37     {
     38         return left + ((right - left) >> 1);
     39     }
     40 } tree[MAXN * 4];
     41 
     42 void pushUp(int root)
     43 {
     44     tree[root].sum = (tree[L(root)].sum + tree[R(root)].sum) % MOD;
     45     tree[root].same = tree[L(root)].same && tree[R(root)].same;
     46     //tree[root].cnt = min(tree[L(root)].cnt, tree[R(root)].cnt);
     47 }
     48 
     49 void build(int root, int left, int right)
     50 {
     51     tree[root].left = left;
     52     tree[root].right = right;
     53     if (left == right) {
     54         tree[root].sum = numbers[left];
     55         tree[root].same = false;
     56         //tree[root].cnt = 0;
     57         return;
     58     }
     59     int mid = tree[root].mid();
     60     build(L(root), left, mid);
     61     build(R(root), mid + 1, right);
     62     pushUp(root);
     63 }
     64 
     65 ULL query(int root, int left, int right)
     66 {
     67     if (tree[root].left == left && tree[root].right == right) {
     68         return tree[root].sum;
     69     }
     70     int mid = tree[root].mid();
     71     if (right <= mid) {
     72         return query(L(root), left, right);
     73     } else if (mid < left) {
     74         return query(R(root), left, right);
     75     } else {
     76         return (query(L(root), left, mid) + query(R(root), mid + 1, right)) % MOD;
     77     }
     78 }
     79 
     80 void update(int root, int left, int right, int add)
     81 {
     82     //重点,如区间内所有数字乘方取模已经不变,则无需更新
     83     if (tree[root].same) {
     84     //也可以用乘方次数,问题是怎么知道这个数字捏?
     85     //if (tree[root].cnt > 30) {
     86         return;
     87     }
     88     if (tree[root].left == tree[root].right) {
     89         //直接乘会超限
     90         //ULL tmp = tree[root].sum * tree[root].sum % MOD;
     91         ULL tmp = squareMod(tree[root].sum);
     92         if (tmp == tree[root].sum) {
     93             tree[root].same = true;
     94             return;
     95         }
     96         //++tree[root].cnt;
     97         tree[root].sum = tmp;
     98         return;
     99     }
    100     int mid = tree[root].mid();
    101     if (right <= mid) {
    102         update(L(root), left, right, add);
    103     } else if (left > mid) {
    104         update(R(root), left, right, add);
    105     } else {
    106         update(L(root), left, mid, add);
    107         update(R(root), mid + 1, right, add);
    108     }
    109     pushUp(root);
    110 }
    111 
    112 int main()
    113 {
    114 //    printf("%lld
    ", mod);
    115 //    printf("%lld
    ", MOD);
    116 //    test();
    117     int t;
    118     int n, m;
    119     int l, r;
    120     int i;
    121     ULL s;
    122     int cas = 0;
    123     scanf("%d", &t);
    124     while (t--) {
    125         scanf("%d%d", &n, &m);
    126         for (i = 1; i <= n; ++i) {
    127             scanf("%llu", &numbers[i]);
    128         }
    129         build(1, 1, n);
    130         printf("Case #%d:
    ", ++cas);
    131         s = 0;
    132         for (i = 0; i < m; ++i) {
    133             scanf("%d%d", &l, &r);
    134             //printf("%d
    ", query(1, l, r));
    135             s = (s + query(1, l, r)) % MOD;
    136             printf("%llu
    ", s);
    137             update(1, l, r, 2);
    138         }
    139     }
    140     return 0;
    141 }
  • 相关阅读:
    linux所有命令失效的解决办法
    第一章 网络基础知识
    RNQOJ 数列
    RNQOJ Jam的计数法
    RNQOJ 开心的金明
    RQNOJ 明明的随机数
    分类讨论的技巧
    Unity 碰撞检测
    Unity --yield return
    Unity 移动方式总结
  • 原文地址:https://www.cnblogs.com/gongpixin/p/6786279.html
Copyright © 2020-2023  润新知