CF311D Interval Cubing 数学、线段树
数学太重要了。。有些人知道点结论就喜欢搞个数学包装水题,欺负吾等数学学渣啊。。。
这是个线段树的经典题目,记录某段被更新了多少次(lazy tag)、求区段和。
由于每个点的状态只有0到47,在建树的时候就把每个点的状态都求好,记录一个偏移量,每次该区间的实际值就是该偏移量的状态(t[now].sum[cnt])。
要注意更新的时候要从下到上都更新一遍。复杂度是O(n*T+q*T*log(n)),CF的机子就是快。。
然后就很简单了。
什么,最重要的还没说?
什么费马小定理啊,因为a^(p-1)%p==1,这样a^x==a^(x%(p-1)),
还有神马周期性啊,因为(3^48)%(95542721-1)==1,靠这也能看出来?好吧,我知道这叫经验。
数学太重要了。。有些人知道点结论就喜欢搞个数学包装水题,欺负吾等数学学渣啊。。。
这是个线段树的经典题目,记录某段被更新了多少次(lazy tag)、求区段和。
由于每个点的状态只有0到47,在建树的时候就把每个点的状态都求好,记录一个偏移量,每次该区间的实际值就是该偏移量的状态(t[now].sum[cnt])。
要注意更新的时候要从下到上都更新一遍。复杂度是O(n*T+q*T*log(n)),CF的机子就是快。。
然后就很简单了。
什么,最重要的还没说?
什么费马小定理啊,因为a^(p-1)%p==1,这样a^x==a^(x%(p-1)),
还有神马周期性啊,因为(3^48)%(95542721-1)==1,靠这也能看出来?好吧,我知道这叫经验。
这样a^(3^x)==a^(3^(x%48)),也就是说每个点的状态只有ai,ai^3..ai^(3^47)而且以周期为48循环的。
脑抽线段树某处写错TLE无数次。。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ls (now<<1)
#define rs (now<<1|1)
#define NN 101000
#define f(x) ((long long)x*x%mod*x%mod)
#define mm(x) (x>=48?(x-48):x)
#define md(x) while(x>=48) x-=48;
const int mod=95542721;
int n,a[NN];
int tcnt;
struct segnode{
int l,r;
int sum[50];
int cnt,add;
}t[NN*4];
void build(int l,int r,int now){
int i;
t[now].l=l;t[now].r=r;
t[now].cnt=t[now].add=0;
if (l==r){
t[now].sum[0]=a[l];
for(i=1;i<48;++i){
t[now].sum[i]=f(t[now].sum[i-1]);
}
return;
}
int mid=(l+r)/2;
build(l,mid,ls);
build(mid+1,r,rs);
for(i=0;i<48;++i) t[now].sum[i]=(t[ls].sum[i]+t[rs].sum[i])%mod;
}
void lazy(int now){
if (t[now].add==0||t[now].l==t[now].r) return;
int k=t[now].add;
t[ls].cnt+=k;t[ls].add+=k;
t[rs].cnt+=k;t[rs].add+=k;
md(t[ls].cnt);md(t[ls].add);
md(t[rs].cnt);md(t[rs].add);
t[now].add=0;
}
void update(int l,int r,int now){
int i;
if (t[now].l==l&&t[now].r==r){
t[now].add+=1;
t[now].cnt+=1;
md(t[now].cnt);md(t[now].add);
return;
}
lazy(now);
int mid=(t[now].l+t[now].r)/2;
if (r<=mid){update(l,r,ls);}
else if (l>mid) {update(l,r,rs);}
else {update(l,mid,ls);update(mid+1,r,rs);}
t[now].cnt=0;
for(i=0;i<48;++i) t[now].sum[i]=(t[ls].sum[mm(i+t[ls].cnt)]+t[rs].sum[mm(i+t[rs].cnt)])%mod;
}
int query(int l,int r,int now){
if (t[now].l==l&&r==t[now].r){
return t[now].sum[mm(t[now].cnt)];
}
lazy(now);
int mid=(t[now].l+t[now].r)/2;
if (r<=mid) return query(l,r,ls);
else if (l>mid) return query(l,r,rs);
else {return (query(l,mid,ls)+query(mid+1,r,rs))%mod;}
}
int main(){
//freopen("311Din.txt","r",stdin);
int i,aa,bb,o,q;
scanf("%d",&n);
for(i=1;i<=n;++i){
scanf("%d",&a[i]);
}
build(1,n,1);
scanf("%d",&q);
for(i=1;i<=q;++i){
scanf("%d%d%d",&o,&aa,&bb);
if (o==1) {printf("%d\n",query(aa,bb,1));}
else {update(aa,bb,1);}
}
return 0;
}