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(1≤i≤n). 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(T≤5), denoting the number of test cases.

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

The next line contains n integers ai(0≤ai<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(1≤l≤r≤n), 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次就会进入一个不变的数。
怎么知道最后会不变的...坑爹
 #include <bits/stdc++.h>
using namespace std; #define L(root) ((root) << 1)
#define R(root) (((root) << 1) | 1) #define LL long long
#define ULL unsigned long long
//const long long mod=((1ll<<63)-(1ll<<31));//这是个什么数 const ULL MOD = 9223372034707292160ULL; //乘法转加法
ULL squareMod(ULL a)
{
ULL b = a;
ULL sum = ;
while (b) {
if (b & ) {
sum = (sum + a) % MOD;
}
a = (a + a) % MOD;
b >>= ;
}
return sum;
} const int MAXN = 1e5 + ;
ULL numbers[MAXN]; struct Node {
int left, right;
ULL sum;
bool same;//
//int cnt;//
int mid()
{
return left + ((right - left) >> );
}
} tree[MAXN * ]; void pushUp(int root)
{
tree[root].sum = (tree[L(root)].sum + tree[R(root)].sum) % MOD;
tree[root].same = tree[L(root)].same && tree[R(root)].same;
//tree[root].cnt = min(tree[L(root)].cnt, tree[R(root)].cnt);
} void build(int root, int left, int right)
{
tree[root].left = left;
tree[root].right = right;
if (left == right) {
tree[root].sum = numbers[left];
tree[root].same = false;
//tree[root].cnt = 0;
return;
}
int mid = tree[root].mid();
build(L(root), left, mid);
build(R(root), mid + , right);
pushUp(root);
} ULL query(int root, int left, int right)
{
if (tree[root].left == left && tree[root].right == right) {
return tree[root].sum;
}
int mid = tree[root].mid();
if (right <= mid) {
return query(L(root), left, right);
} else if (mid < left) {
return query(R(root), left, right);
} else {
return (query(L(root), left, mid) + query(R(root), mid + , right)) % MOD;
}
} void update(int root, int left, int right, int add)
{
//重点,如区间内所有数字乘方取模已经不变,则无需更新
if (tree[root].same) {
//也可以用乘方次数,问题是怎么知道这个数字捏?
//if (tree[root].cnt > 30) {
return;
}
if (tree[root].left == tree[root].right) {
//直接乘会超限
//ULL tmp = tree[root].sum * tree[root].sum % MOD;
ULL tmp = squareMod(tree[root].sum);
if (tmp == tree[root].sum) {
tree[root].same = true;
return;
}
//++tree[root].cnt;
tree[root].sum = tmp;
return;
}
int mid = tree[root].mid();
if (right <= mid) {
update(L(root), left, right, add);
} else if (left > mid) {
update(R(root), left, right, add);
} else {
update(L(root), left, mid, add);
update(R(root), mid + , right, add);
}
pushUp(root);
} int main()
{
// printf("%lld\n", mod);
// printf("%lld\n", MOD);
// test();
int t;
int n, m;
int l, r;
int i;
ULL s;
int cas = ;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
for (i = ; i <= n; ++i) {
scanf("%llu", &numbers[i]);
}
build(, , n);
printf("Case #%d:\n", ++cas);
s = ;
for (i = ; i < m; ++i) {
scanf("%d%d", &l, &r);
//printf("%d\n", query(1, l, r));
s = (s + query(, l, r)) % MOD;
printf("%llu\n", s);
update(, l, r, );
}
}
return ;
}
上一篇:Doom HDU - 5239 (找规律+线段树)


下一篇:[Aaronyang] 写给自己的WPF4.5 笔记12[自定义控件-AyImageButton的过程 2/4]