题意:一共有n个门,每个门都有一个权值,每次能打开从 l 到 r 的门,有个屏幕能在打开这些门之后把这些门里的值累计起来。每打开一扇门,这个门的权值就变为自身的平方。所有的值对p=9223372034707292160取余即是最后答案。
想法:利用线段树来更新区间的值并求和。看了题解才发现一个数自身平方到29次对p的取余就会不变。
代码如下:
#include
#include
#include
#include
#include
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=100000+100;
typedef unsigned long long ll;
const ll mod=9223372034707292160;
ll sum[maxn<<2];
int cnt[maxn<<2];
void pushup(int rt)
{
sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod;
cnt[rt]=min(cnt[rt<<1],cnt[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l==r) {
scanf("%I64u",&sum[rt]);
cnt[rt]=0;
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R) {
return sum[rt];
}
ll cnt=0;
int m=(l+r)>>1;
if(L<=m) cnt+=query(L,R,lson);
if(cnt>mod) cnt-=mod;
if(R>m) cnt+=query(L,R,rson);
if(cnt>mod) cnt-=mod;
return cnt;
}
ll quick_add(ll a,ll n)
{
if(n==0)
return 0;
ll 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 update(int L,int R,int l,int r,int rt)
{
if(cnt[rt]>=30) {
return ;
}
if(l==r) {
sum[rt]=quick_add(sum[rt],sum[rt]);
cnt[rt]++;
return ;
}
int m=(l+r)>>1;
if(L<=m) {
update(L,R,lson);
}
if(R>m) {
update(L,R,rson);
}
pushup(rt);
}
int main()
{
int T,L,R,n,m,cas=1;
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
build(1,n,1);
ll ans=0;
printf("Case #%d:\n",cas++);
for(int i=0;i=mod)
ans-=mod;
printf("%I64u\n",ans);
update(L,R,1,n,1);
}
}
return 0;
}