版权声明:写得不好,随便转载,但请注明出处,感激不尽 https://blog.csdn.net/xyc1719/article/details/82944692
什么破标题
【一句话题意】 给定一个长度为n的序列。有m个询问,每次询问[l,r]的序列和,并将区间内所有数平方。
【分析】通过打表发现当一个数平方几十次之后他就会陷入一个平方不变的循环。我们可以暴力修改每个数,并用线段树(树状数组或者分块)维护区间和,用并查集优化修改时的扫描次数。(这是第几次用并查集合并区间了,管他呢)。
Code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL mod=2305843008676823040;
const LL maxn=2<<17;
LL done[maxn],f[maxn],a[maxn];
LL t[maxn<<2];//segment tree
LL n,m;
inline void read(LL &x){
x=0;char tmp=getchar();
while(tmp<'0'||tmp>'9')tmp=getchar();
while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
}
inline LL mul(LL x,LL p){
LL ret=0;
while(p>0){
if(p&1) ret=(ret+x)%mod;
x=(x<<1)%mod;
p=p>>1;
}
return ret;
}
void build(LL num,LL l,LL r){
if(l==r){t[num]=a[l];return ;}
LL mid=l+r>>1;
build(num<<1,l,mid);
build(num<<1|1,mid+1,r);
t[num]=(t[num<<1]+t[num<<1|1])%mod;
}
inline LL find(LL x){
if(f[x]!=x) f[x]=find(f[x]);
return f[x];
}
inline void resive(LL num,LL l,LL r,LL pos){
if(l==r){
t[num]=a[pos];
return ;
}
LL mid=l+r>>1;
if(pos<=mid) resive(num<<1,l,mid,pos);
else resive(num<<1|1,mid+1,r,pos);
t[num]=(t[num<<1]+t[num<<1|1])%mod;
return ;
}
inline LL query(LL num,LL l,LL r,LL stdl,LL stdr){
if(stdl<=l&&r<=stdr){
return t[num];
}
LL mid=l+r>>1,ret=0;
if(mid>=stdl) ret+=query(num<<1,l,mid,stdl,stdr);
if(mid+1<=stdr) ret+=query(num<<1|1,mid+1,r,stdl,stdr);
ret%=mod;
return ret;
}
int main(){
freopen("ak.in","r",stdin);
freopen("ak.out","w",stdout);
cin>>n>>m;
for(LL i=1;i<=n;i++)read(a[i]);
build(1,1,n);
for(LL i=1;i<=n;i++)f[i]=i;
for(LL i=1;i<=m;i++){
LL l,r,pos;read(l),read(r),pos=r;
printf("%lld\n",query(1,1,n,l,r));
while(l<=pos){
pos=find(pos);
if(done[pos]&&pos<l){
pos--;
continue;
}
if(mul(a[pos],a[pos])==a[pos]){
done[pos]=1;
if(done[pos-1])f[pos]=find(pos-1);
}
else{
a[pos]=mul(a[pos],a[pos]);
resive(1,1,n,pos);
}
pos--;
}
}
return 0;
}