Doom
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 1401 Accepted Submission(s): 368
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.
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.
For more details you can take a look at the example.
4 4
2 3 4 5
1 2
2 3
3 4
1 4
1 3
2
1 1
1 1
1 1
5
18
39
405
Case #2:
2
6
22
#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 ;
}