您的位置:首页 > 其它

HDU 5239 上海大都会 D题(线段树+数论)

2015-05-30 10:18 501 查看
打表,发现规律是存在一定次数(较小)后,会出现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;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: