CF311D Interval Cubing 数学、线段树

来源:互联网 发布:php 删除文本文件 编辑:程序博客网 时间:2024/05/22 07:52
CF311D Interval Cubing 数学、线段树

数学太重要了。。有些人知道点结论就喜欢搞个数学包装水题,欺负吾等数学学渣啊。。。



CF有官方题解,不过我还是记录一下吧。
这是个线段树的经典题目,记录某段被更新了多少次(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;}

原创粉丝点击