暑假集训中期测试 Problem G: 维护序列 (线段树)

Description

    现在有一个N个整数组成的序列,这N个整数的标号分别为1, 2, ..., N,对这个序列一共进行两类操作:

    ① 1 x y:表示将第x个和第y个(包括x、y)整数之间的所有整数的二进制的最低位的1变为0,如果某个整数的值为0,则不对这个整数做任何改变。
    ② 2 x y :表示你需要回答第x个和第y个(包括x、y)整数之间的所有整数异或的结果。

Input

    输入包含多组测试数据。
    对于每组测试数据,第一行包含两个正整数N(2<=N<=10^4)、M(1<=M<=10^5),表示这个序列一共有N个整 数,你需要处理M次操作。接下来一行一共有N个不超过2^30的非负整数,依次描述了这个序列中各个整数的初始值。再接下来一共有M行,每行均描述了一种 操作。

Output

    对于每个第②类操作,用一行输出一个整数表示回答的结果。

Sample Input

3 4
3 6 0
2 2 2
2 1 2
1 1 3
2 1 3

Sample Output

6
5
6
 
分析:一开始总在想这题中对区间的操作如何更新区间的关键信息(如果一个一个更新显然会超时),硬是没想出个名堂。后来看了标程才明白,原来对区间的更新就是一个一个进行的,只不过每段区间的更新次数是有一个上限的(29),所以,在每个区间保存一个关键信息(区间中所有元素是否均为0)指示该区间是否需要更新就可以避免许多不必要的更新,从而降低时间复杂度。
View Code
#include <stdio.h>
#define N 10001
int n,m;
int a[N];
int ans[4*N];
bool f[4*N];
void update(int cur)
{
    int ls=cur<<1,rs=cur<<1|1;
    ans[cur]=ans[ls]^ans[rs];
    f[cur]=f[ls]|f[rs];
}
void build(int cur,int x,int y)
{
    int mid=x+y>>1,ls=cur<<1,rs=cur<<1|1;
    if(x==y)
    {
        f[cur]=ans[cur]=a[x];
        return;
    }
    build(ls,x,mid);
    build(rs,mid+1,y);
    update(cur);
}
void change(int cur,int x,int y,int s,int t)
{
    int mid=x+y>>1,ls=cur<<1,rs=cur<<1|1;
    if(!f[cur]) return;
    if(x==y)
    {
        ans[cur]^=ans[cur]&(-ans[cur]);
        f[cur]=ans[cur];
        return;
    }
    if(mid>=s)  change(ls,x,mid,s,t);
    if(mid+1<=t)    change(rs,mid+1,y,s,t);
    update(cur);
}
void query(int cur,int x,int y,int s,int t,int &ret)
{
    int mid=x+y>>1,ls=cur<<1,rs=cur<<1|1;
    if(x>=s && y<=t)
    {
        ret^=ans[cur];
        return;
    }
    if(mid>=s)  query(ls,x,mid,s,t,ret);
    if(mid+1<=t)    query(rs,mid+1,y,s,t,ret);
}
void solve(int opt,int x,int y)
{
    int ret=0;
    if(x>y) {int tmp=x;x=y;y=tmp;}
    if(opt==1)  change(1,1,n,x,y);
    else    query(1,1,n,x,y,ret),printf("%d\n",ret);
}
int main()
{
    int opt,x,y,i;
    while(~scanf("%d%d",&n,&m))
    {
        for(i=1;i<=n;i++)   scanf("%d",&a[i]);
        build(1,1,n);
        while(m--)
        {
            scanf("%d%d%d",&opt,&x,&y);
            solve(opt,x,y);
        }
    }
    return 0;
}

 

 
posted @ 2012-07-30 17:40  BeatLJ  阅读(218)  评论(0编辑  收藏  举报