思路:打个表之后发现最多操作29次,之后区间的值就不会再改变,然后就是一个线段树了
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define maxn 100005 + 10
#define mod 9223372034707292160ULL
#define lson i<<1,l,m
#define rson (i<<1)|1,m+1,r
ULL a[maxn << 2];
int cnt[maxn << 2];
ULL sum[maxn << 2];
ULL quick_add(ULL a, ULL n){
if(n == 0)
return 0;
ULL sum = quick_add(a, n/2);
sum = (sum+sum);
if(sum >= mod)
sum -= mod;
if(n & 1)
sum = (sum + a);
if(sum >= mod)
sum -= mod;
return sum;
}
void push_up(int i){
sum[i] = (sum[i << 1] + sum[i << 1 | 1]) % mod;
cnt[i] = min(cnt[i << 1], cnt[i << 1 | 1]);
}
void build(int i,int l,int r)
{
if(l == r)
{
cnt[i] = 0;
sum[i] = a[l];
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
push_up(i);
}
ULL query(int ql,int qr,int i,int l,int r)
{
if(ql <= l && qr >= r)
return sum[i];
int m = (l + r) >> 1;
ULL s = 0;
if(ql <= m) s = (s + query(ql,qr,lson));
if(s >= mod) s -= mod;
if(qr > m) s = (s + query(ql,qr,rson));
if(s >= mod) s -= mod;
return s;
}
void update(int ql,int qr,int i,int l,int r)
{
if(cnt[i] >= 30)
return ;
if(l == r)
{
sum[i] = quick_add(sum[i], sum[i]);
cnt[i]++;
return ;
}
int m = (l + r) >> 1;
if(ql <= m)
update(ql,qr,lson);
if(qr> m)
update(ql,qr,rson);
push_up(i);
}
int main ()
{
int t;
int cas = 1;
scanf("%d", &t);
while(t--)
{
int n, q;
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; i++)
scanf("%llu", &a[i]);
build(1, 1,n);
ULL s = 0;
printf("Case #%d:\n", cas++);
while(q--)
{
int l, r;
scanf("%d%d", &l, &r);
s += query(l,r,1,1,n);
if(s >= mod) s -= mod;
printf("%llu\n", s);
update(l,r,1,1,n);
}
}
return 0;
}