zoukankan      html  css  js  c++  java
  • Coderforces 242E XOR on Segment

    题意:给定一个序列,要求完成俩个操作

    1)查询区间[l,r] 的和

    2)区间更新, 区间每一个数都异或一个数x

    对每一个查询输出结果

    分析:对区间更新和查询这种操作,比较明显的就想到了线段树。区间查询比较简单,关键是区间更新该如何解决。

    我们为线段数的每一个节点开一个cnt[20] 的数组,保存该区间内每一个数二进制位上1的个数,cnt[0] 表示对应区间内所有数第一个二进制数上1的个数和,这样,针对每一个异或操作,我们可以这样解决:

    		for(int i = 0; i < L; ++i)
    		{
    			if(!(v & ( 1 << i) )) continue;//针对异或操作的性质,如果v的第i位为0,则这个区间内,第i位上的1的个数不变;
                                    //若第i位为1,则第i为上1 的个数和0 的个数互换 p[k].cnt[i] = p[k].r-p[k].l + 1 - p[k].cnt[i]; }

    这样,在计算区间和时

    		for(int i = 0; i < L; ++i)
    			ans += ((p[k].cnt[i] * 1ll) << i);
    

    当然,要加速对区间更新的操作,肯定要运用lazy的思想

    完整代码
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    const int N = 100000 + 10;
    const int L = 20; 
    
    struct Node
    {
        int l,r;
        int c,cnt[L];//cnt[i] 表示区间[l,r]内二进制第i位上1的个数
    }p[3*N];
    int que[N];
     
    void build(int k,int s,int t)
    {
        int kl, kr, mid;
        p[k].l = s; p[k].r = t;p[k].c = 0;
        if(s == t) {
            for(int i = 0; i < L; ++i)
            {
                if(que[s] & ( 1 << i ))  
                    p[k].cnt[i] = 1;
            }
            return ;
        }
        mid=(s + t) >> 1; kl = k << 1; kr = kl + 1;
        build(kl, s, mid);
        build(kr, mid+1, t);
        for(int i = 0; i < L; ++i)
            p[k].cnt[i] = p[kl].cnt[i] + p[kr].cnt[i];
    }
    
    void Push_Down(int k, int v)
    {
            p[k].c ^= v;
            for(int i = 0; i < L; ++i)
            {
                if(!(v & ( 1 << i) )) continue;
                p[k].cnt[i] = p[k].r-p[k].l + 1 - p[k].cnt[i];
            }
    }
     
    void insert(int k,int s,int t,int v)
    {
        if(s <= p[k].l&& t >= p[k].r)
        {
            Push_Down(k, v);
            return ;
        }
        else {
    
            int mid=(p[k].r + p[k].l) >> 1, kl = k << 1, kr = kl + 1;
            if(p[k].c != 0)
            {
                Push_Down(kl, p[k].c);
                Push_Down(kr, p[k].c);
                p[k].c = 0;
            }
            if(s <= mid) insert(kl, s, t, v);
            if(t > mid) insert(kr, s, t, v);
            for(int i = 0; i < L; ++i)
                p[k].cnt[i] = p[kr].cnt[i] + p[kl].cnt[i];
        }
    }
     
    __int64 query(int k,int s,int t)
    {
        if(s <= p[k].l && t >= p[k].r)
        {
            __int64 ans = 0;
            for(int i = 0; i < L; ++i)
                ans += ((p[k].cnt[i] * 1ll) << i);
            return ans;
        }
    
        int mid=(p[k].r + p[k].l) >> 1,kl = k << 1,kr = kl + 1;
    
        if(p[k].c)
        {
            Push_Down(kl, p[k].c);
            Push_Down(kr, p[k].c);
            p[k].c = 0;
        }
        __int64 a = 0,b = 0;
        if(s <= mid) a = query(kl,s,t);
        if(t > mid) b = query(kr,s,t);
        for(int i = 0; i < L; ++i)
            p[k].cnt[i] = p[kl].cnt[i] + p[kr].cnt[i];
        return a + b;
    }
     
    int main()
    {
        int i,n,m,a,b,t,k;
        scanf("%d",&n);
            for(i = 1; i <= n; ++i) scanf("%d",que + i);
            build(1,1,n);
            scanf("%d",&m);
            while(m--)
            {
                scanf("%d",&k);
                if(k == 1)
                {
                   scanf("%d %d",&a,&b);
                   printf("%I64d\n",query(1,a,b));
                }
                else
                {
                   scanf("%d %d %d",&a,&b,&t);
                   if(t != 0)
                       insert(1,a,b,t);
                }
            }
        return 0;
    }
  • 相关阅读:
    [置顶] Windows Phone后台音乐详解一
    Android应用开发学习笔记之BroadcastReceiver
    二维码闪电登录流程详解,附demo(1/2)
    C#利用Lambda和Expression实现数据的动态绑定
    从M个数中随机选出N个数的所有组合,有序,(二)
    3DShader之立方体环境映射(cubic environment mapping)
    二维码闪电登录流程详解,附demo(2/2)
    oracle 分区表exchange原理
    禁止页面复制功能 js禁止复制 禁用页面右键菜单
    sleep与信号唤醒的问题 & 内核对信号的处理方式
  • 原文地址:https://www.cnblogs.com/nanke/p/2952610.html
Copyright © 2011-2022 走看看