暑假集训每日一题0711 (线段树)

维护一个整数序列,支持以下操作:
1 x v : 将第x个整数的值修改为v;
2 x y : 查询区间[x,y]之间的最小值;
3 x y : 查询区间[x,y]之间的最大值;
4 x y : 查询区间[x,y]内的整数和。

数据保证查询结果均在int范围之内,但中间结果是否可能溢出呢?我交的程序没考虑这个也AC了。

通过这题还发现一个奇怪的现象,用memset初始化的程序跑了2s多,而用for循环初始化的程序才跑468ms……

for循环初始化(468ms)
#include <stdio.h>

#include <string.h>

#define MIN(a,b) ((a)<(b)?(a):(b))

#define MAX(a,b) ((a)>(b)?(a):(b))

#define INF 0x7fffffff

#define N 100010

int D,n;

int v[N],min[4*N],max[4*N],sum[4*N];

void init()

{

    int i;

    for(i=1;i<2*D;i++)

    {

        min[i]=INF;

        max[i]=-INF;

        sum[i]=0;

    }

    for(D=1;D<n+2;D<<=1);

    for(i=1;i<=n;i++)

    {

        min[D+i]=max[D+i]=sum[D+i]=v[i];

    }

    for(i=D-1;i^1;i--)

    {

        min[i]=MIN(min[i<<1],min[i<<1|1]);

        max[i]=MAX(max[i<<1],max[i<<1|1]);

        sum[i]=sum[i<<1]+sum[i<<1|1];

    }

}

void update(int k,int v)

{

    int i;

    min[D+k]=max[D+k]=sum[D+k]=v;

    for(i=D+k;i^1;i>>=1)

    {

        min[i>>1]=MIN(min[i],min[i^1]);

        max[i>>1]=MAX(max[i],max[i^1]);

        sum[i>>1]=sum[i]+sum[i^1];

    }

}

void getmin(int x,int y)

{

    int i=D+x-1,j=D+y+1,ret=INF;

    for(;i^j^1;i>>=1,j>>=1)

    {

        if(~i&1)    ret=MIN(ret,min[i^1]);

        if(j&1) ret=MIN(ret,min[j^1]);

    }

    printf("%d\n",ret);

}

void getmax(int x,int y)

{

    int i=D+x-1,j=D+y+1,ret=-INF;

    for(;i^j^1;i>>=1,j>>=1)

    {

        if(~i&1)    ret=MAX(ret,max[i^1]);

        if(j&1) ret=MAX(ret,max[j^1]);

    }

    printf("%d\n",ret);

}

void getsum(int x,int y)

{

    int i=D+x-1,j=D+y+1,ret=0;

    for(;i^j^1;i>>=1,j>>=1)

    {

        if(~i&1)    ret+=sum[i^1];

        if(j&1) ret+=sum[j^1];

    }

    printf("%d\n",ret);

}

int main()

{

    int i,m,opt,x,y;

    while(~scanf("%d",&n))

    {

        for(i=1;i<=n;i++)   scanf("%d",&v[i]);

        scanf("%d",&m);

        init();

        for(i=0;i<m;i++)

        {

            scanf("%d%d%d",&opt,&x,&y);

            switch(opt)

            {

                case 1: update(x,y);    break;

                case 2: getmin(x,y);    break;

                case 3: getmax(x,y);    break;

                case 4: getsum(x,y);    break;

            }

        }

    }

    return 0;

}
memset初始化(2s多)
#include <stdio.h>

#include <string.h>

#define MIN(a,b) ((a)<(b)?(a):(b))

#define MAX(a,b) ((a)>(b)?(a):(b))

#define INF 0x7fffffff

#define N 100010

int D,n;

int v[N],min[4*N],max[4*N],sum[4*N];

void init()

{

    int i;

    memset(min,0x3f,sizeof(min));

    memset(max,0xc3,sizeof(max));

    memset(sum,0,sizeof(sum));

    for(D=1;D<n+2;D<<=1);

    for(i=1;i<=n;i++)

    {

        min[D+i]=max[D+i]=sum[D+i]=v[i];

    }

    for(i=D-1;i^1;i--)

    {

        min[i]=MIN(min[i<<1],min[i<<1|1]);

        max[i]=MAX(max[i<<1],max[i<<1|1]);

        sum[i]=sum[i<<1]+sum[i<<1|1];

    }

}

void update(int k,int v)

{

    int i;

    min[D+k]=max[D+k]=sum[D+k]=v;

    for(i=D+k;i^1;i>>=1)

    {

        min[i>>1]=MIN(min[i],min[i^1]);

        max[i>>1]=MAX(max[i],max[i^1]);

        sum[i>>1]=sum[i]+sum[i^1];

    }

}

void getmin(int x,int y)

{

    int i=D+x-1,j=D+y+1,ret=INF;

    for(;i^j^1;i>>=1,j>>=1)

    {

        if(~i&1)    ret=MIN(ret,min[i^1]);

        if(j&1) ret=MIN(ret,min[j^1]);

    }

    printf("%d\n",ret);

}

void getmax(int x,int y)

{

    int i=D+x-1,j=D+y+1,ret=-INF;

    for(;i^j^1;i>>=1,j>>=1)

    {

        if(~i&1)    ret=MAX(ret,max[i^1]);

        if(j&1) ret=MAX(ret,max[j^1]);

    }

    printf("%d\n",ret);

}

void getsum(int x,int y)

{

    int i=D+x-1,j=D+y+1,ret=0;

    for(;i^j^1;i>>=1,j>>=1)

    {

        if(~i&1)    ret+=sum[i^1];

        if(j&1) ret+=sum[j^1];

    }

    printf("%d\n",ret);

}

int main()

{

    int i,m,opt,x,y;

    while(~scanf("%d",&n))

    {

        for(i=1;i<=n;i++)   scanf("%d",&v[i]);

        scanf("%d",&m);

        init();

        for(i=0;i<m;i++)

        {

            scanf("%d%d%d",&opt,&x,&y);

            switch(opt)

            {

                case 1: update(x,y);    break;

                case 2: getmin(x,y);    break;

                case 3: getmax(x,y);    break;

                case 4: getsum(x,y);    break;

            }

        }

    }

    return 0;

}

你可能感兴趣的:(线段树)