标签:
打表,发现规律是存在一定次数(较小)后,会出现a=(a*a)%p。可以明显地发现本题与线段树有关。设置标记flag,记录本段内的数是否均已a=a*a%p。若是,则不需更新,否则更新有叶子结点,再pushup。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL unsigned long long
using namespace std;
const LL p=9223372034707292160uLL;
const int N=100050;
int n;
LL seg[N<<2],s;
bool flag[N<<2];
void build(int rt,int l,int r){
flag[rt]=false;
if(l==r){
scanf("%llu",&seg[rt]);
// cout<<l<<"="<<seg[rt]<<endl;
return ;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
seg[rt]=(seg[rt<<1]+seg[rt<<1|1])%p;
}
LL mul(LL a,LL b){
LL res=0;
while(b){
if(b&1) res=(res+a)%p;
b>>=1;
a=(a+a)%p;
}
return res;
}
void update(int rt,int l,int r,int L,int R){
if(flag[rt]&&l<=L&&R<=r){
s=(s+seg[rt])%p;
return ;
}
if(L==R){
s=(s+seg[rt])%p;
LL tmp=mul(seg[rt],seg[rt]);
if(seg[rt]==tmp){
flag[rt]=true;
}
seg[rt]=tmp;
return ;
}
int m=(L+R)>>1;
if(r<=m){
update(rt<<1,l,r,L,m);
}
else if(l>=m+1) update(rt<<1|1,l,r,m+1,R);
else{
update(rt<<1,l,r,L,m);
update(rt<<1|1,l,r,m+1,R);
}
flag[rt]=flag[rt<<1]&flag[rt<<1|1];
seg[rt]=(seg[rt<<1]+seg[rt<<1|1])%p;
}
int main(){
int T,icase=0,k,l,r;
scanf("%d",&T);
while(T--){
s=0;
scanf("%d%d",&n,&k);
build(1,1,n);
printf("Case #%d:\n",++icase);
for(int i=1;i<=k;i++){
scanf("%d%d",&l,&r);
update(1,l,r,1,n);
printf("%llu\n",s);
}
}
return 0;
}
标签:
原文地址:http://www.cnblogs.com/jie-dcai/p/4539908.html