• 暑假集训中期测试 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;
    }
     
  • 相关阅读:
    【汇编程序】出地址为BUF的5个字符数组的内容之和
    Ugly Number
    Best Time to Buy and Sell Stock IV****
    Best Time to Buy and Sell Stock III
    Best Time to Buy and Sell Stock
    Best Time to Buy and Sell Stock II
    House Robber II
    Contain Duplicate III*******
    Contain Duplicate II
    Contain Duplicate
  • 原文地址:https://www.cnblogs.com/algorithms/p/2615660.html
Copyright © 2020-2023  润新知