zoukankan      html  css  js  c++  java
  • Codeforces 242E. XOR on Segment (二维线段树 lazy操作 xor)

    题目链接:

    http://codeforces.com/problemset/problem/242/E

    题意:

    给出一个序列,有两种操作,一种是计算l到r的和,另一种是让l到r的数全部和x做异或运算。

    思路:

    from: http://blog.csdn.net/u013912596/article/details/39006317

    很显然直接暴力是不可能的,又是两种操作,又想到了线段树。。但是这并不简单,异或操作该怎么处理?
    异或是一种位运算,如果x的第j位是1,那么说明l到r的每个数的第j位都要反转,(0^1=1,1^1=0),如果是0,那么不变。既然是位运算,那么可不可以将每一位作为线段树单独维护呢?
    好像可以呢!异或操作的话,相当于是一种区间操作,只需要将l到r的某些位进行反转操作不就行了吗?反转操作什么的,打上lazy tag不就OK啦,求和操作也可以计算出l到r的每一位上有多少个1来算出最后的和。
    好,那么理一下思路,首先确定建立多少个线段树,数的范围是10^6,也就是说,我们最多只需要建立20个线段树即可,1e6最多20位嘛,每一位都是一颗线段树,有n个叶子节点,再写好线段树的bulid,update,query三个函数。每个节点上需要维护两个值,一个是该区间有多少个1(用于求和),一个是该区间是否反转(lazy tag)。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define MS(a) memset(a,0,sizeof(a))
    #define MP make_pair
    #define PB push_back
    const int INF = 0x3f3f3f3f;
    const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
    inline ll read(){
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    //////////////////////////////////////////////////////////////////////////
    const int maxn = 1e5+10;
    
    struct node{
        int l,r,cnt,lazy;
    }p[20][maxn<<2];
    
    ll n,x,two[20];
    int a[maxn][20];
    
    int build(int rt,int l,int r,int na){
        if(l==r){
            p[na][rt] = node{l,r,a[l][na],0};
            return a[l][na];
        }
        int mid = (l+r)/2;
        int res = build(rt<<1,l,mid,na);
        res += build(rt<<1|1,mid+1,r,na);
        p[na][rt] = node{l,r,res,0};
        return res;
    }
    
    void upd(int rt,int l,int r,int na){
        int L = p[na][rt].l, R = p[na][rt].r;
        if(L==l && R==r){
            p[na][rt].lazy = 1-p[na][rt].lazy;
            p[na][rt].cnt = R-L+1-p[na][rt].cnt;
            return ;
        }
        if(p[na][rt].lazy){
            p[na][rt<<1].lazy = 1-p[na][rt<<1].lazy;
            p[na][rt<<1].cnt = p[na][rt<<1].r-p[na][rt<<1].l+1-p[na][rt<<1].cnt;
            p[na][rt<<1|1].lazy = 1-p[na][rt<<1|1].lazy;
            p[na][rt<<1|1].cnt = p[na][rt<<1|1].r-p[na][rt<<1|1].l+1-p[na][rt<<1|1].cnt;
            p[na][rt].lazy = 1-p[na][rt].lazy;    
        }
        int mid = (L+R)/2;
        if(mid >= r) upd(rt<<1,l,r,na);
        else if(mid < l) upd(rt<<1|1,l,r,na);
        else {
            upd(rt<<1,l,mid,na);
            upd(rt<<1|1,mid+1,r,na);
        }
        p[na][rt].cnt = p[na][rt<<1].cnt + p[na][rt<<1|1].cnt;
    }
    
    ll que(int rt,int l,int r,int na){
        int L = p[na][rt].l, R = p[na][rt].r;
        if(l==L && r==R) return p[na][rt].cnt;
        if(p[na][rt].lazy){
            p[na][rt<<1].lazy = 1-p[na][rt<<1].lazy;
            p[na][rt<<1].cnt = p[na][rt<<1].r-p[na][rt<<1].l+1-p[na][rt<<1].cnt;
            p[na][rt<<1|1].lazy = 1-p[na][rt<<1|1].lazy;
            p[na][rt<<1|1].cnt = p[na][rt<<1|1].r-p[na][rt<<1|1].l+1-p[na][rt<<1|1].cnt;
            p[na][rt].lazy = 1-p[na][rt].lazy;        
        }
        ll res = 0;
        int mid = (L+R)/2;
        if(mid >= r) res += que(rt<<1,l,r,na);
        else if(mid < l) res += que(rt<<1|1,l,r,na);
        else res += que(rt<<1,l,mid,na)+que(rt<<1|1,mid+1,r,na);
        return res;
    }
    
    int main(){
        two[0] = 1;
        for(int i=1; i<20; i++) two[i] = two[i-1]*2;
        cin >> n;
        for(int i=1; i<=n; i++){
            cin >> x;
            int j = 0;
            while(x){
                a[i][j++] = x&1;
                x >>= 1;
            }
        }
        for(int i=0; i<20; i++)
            build(1,1,n,i);
        int m = read();
        while(m--){
            int a,b,op = read();
            if(op == 1){
                scanf("%d%d",&a,&b);
                ll sum = 0;
                for(int i=0; i<20; i++)
                    sum += que(1,a,b,i)*two[i];
                printf("%I64d
    ",sum);
            }else{
                int x;
                scanf("%d%d%d",&a,&b,&x);
                int i = 0;
                while(x){
                    if(x&1) upd(1,a,b,i);
                    i++; x>>=1;
                }
            }
        }
    
        return 0;
    }
  • 相关阅读:
    js 遍历EL表达式 list对象
    easyui-datebox 点击事件
    java-启动和关闭.exe程序
    css 样式控制文本过长实现省略号
    java-plupload上传大文件
    .ajax向后台传递数组(转)
    <c:> </c:>
    访问修饰符
    附录A培训实习生-面向对象基础方法重载(3)
    附录A培训实习生-面向对象基础构造方法和带参数的构造方法(2)
  • 原文地址:https://www.cnblogs.com/yxg123123/p/7233226.html
Copyright © 2011-2022 走看看