HDU 5239 DOOM 线段树

来源:互联网 发布:上传视频的软件 编辑:程序博客网 时间:2024/05/19 15:18

HDU 5239 DOOM 线段树

标签(空格分隔): 线段树


题目链接:hdu5239
题意:给定长度为N的序列,有Q个操作,每次操作询问区间[l,r]的和,并将区间的值平方,每次输出所有之前查询答案的和对2^63-2^31取模。
思路:找规律发现任何数平方30次之后模mod都不再变化。于是用线段树维护区间内平方次数最少的元素为多少,弱最小的大于30则不进行操作,直接返回区间和,反之则继续递归直至叶子节点。
代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define Lson o<<1,l,mid#define Rson o<<1|1,mid+1,rconst int maxn =100010;int minv[maxn*4];unsigned long long sum[maxn*4];long long data[maxn];const long long mod=((1ll<<63)-(1ll<<31));void sqr(int i){    long long tp1,tp2;    tp1=tp2=sum[i];    __asm__("movq %1,%%rax\n imulq %2\n idivq %3\n":"=d"(sum[i]):"m"(tp1),"m"(tp2),"m"(mod):"%rax");}unsigned long long modify(int o,int l,int r,int L,int R){    if(minv[o]>31&&L<=l&&R>=r) return sum[o];    unsigned long long ret=0;    if(l==r){        ret=sum[o];        sqr(o);        minv[o]++;        return ret;    }    int mid=(l+r)>>1;    if(L<=mid)ret=(ret+modify(Lson,L,R))%mod;    if(R>mid) ret=(ret+modify(Rson,L,R))%mod;    sum[o]=(sum[o<<1]+sum[o<<1|1])%mod;    minv[o]=min(minv[o<<1],minv[o<<1|1]);    return ret;}void init(int o,int l,int r){    if(l==r){        minv[o]=0;        sum[o]=data[l];        return ;    }    int mid=(l+r)>>1;    init(Lson);init(Rson);    sum[o]=(sum[o<<1]+sum[o<<1|1])%mod;    minv[o]=0;}int main(){    int T,cas=0;//    freopen("data.in","r",stdin);    scanf("%d",&T);    while(T--){        memset(sum,0,sizeof(sum));        printf("Case #%d:\n",++cas);        int n,q,l,r;        unsigned long long ans=0;        scanf("%d%d",&n,&q);        for(int i=1;i<=n;i++)scanf("%I64d",data+i);        init(1,1,n);        while(q--){            scanf("%d%d",&l,&r);            ans=(ans+modify(1,1,n,l,r))%mod;            printf("%I64d\n",(long long)ans);        }    }    return 0;}
0 0
原创粉丝点击