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\n",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;
}
时间: 2024-08-27 17:46:08

Codeforces 242E. XOR on Segment (二维线段树 lazy操作 xor)的相关文章

【BZOJ4785】[Zjoi2017]树状数组 树套树(二维线段树)

[BZOJ4785][Zjoi2017]树状数组 Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1) mod 2. 2 l r,表示询问 sigma(Ai) mod 2,L<=i<=r 尽管那个时候的可怜非常的 simple,但是她还是发现这题可以用树状数组做.当时非常yo

POJ 2155 Matrix (二维线段树)

http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 18143   Accepted: 6813 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. I

HDU1832 二维线段树求最值(模板)

Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 50 Accepted Submission(s): 20   Problem Description 世界上上最远的距离不是相隔天涯海角而是我在你面前可你却不知道我爱你                ―― 张小娴 前段日子,枫冰叶子给Wiskey做了个征婚启事,聘

ZOJ 2859 二维线段树

思路:自己写的第二发二维线段树1A,哈哈,看来对二维的push操作比较了解了:但是还没遇到在两个线段树中同时进行push操作的,其实这题我是想在x维和y维同时进行push操作的,但是想了好久不会,然后看到这题又给出10秒,然后想想在x维线段直接单点查询肯定也过了,然后在第二维就只有pushup操作,在第一维线段树没有pushup操作.要是在第一维也有pushup操作的话,那就不用单点查询那么慢了.不过也A了,想找题即在二维同时进行pushup和pushdown操作的. #include<iost

[POJ2155] Matrix(二维线段树,树套树)

题目链接:http://poj.org/problem?id=2155 题意:给一个01矩阵,两个操作,翻转:子矩阵里每一个数都由0变1,1变0. 查询:查询某一点是0还是1. 一直以为二维线段树就是开一个线段树数组的我- 这题暴力更新每一个小矩形,翻转就+1,最后看看某点的奇偶. 写屎了,特别注意的是在外层查询的时候要先把当前层的内层query掉,接着再向下扩展.这样外层就不用lazy啦 1 #include <algorithm> 2 #include <iostream> 3

poj1195 Mobile phones 二维线段树入门

二维线段树就是树套树,线段树套线段树... #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define lson l,m,rt<<1 #

UVA 11297 Census ——二维线段树

[题目分析] 二维线段树模板题目. 简直就是无比的暴力.时间复杂度为两个log. 标记的更新方式比较奇特,空间复杂度为N^2. 模板题目. [代码] #include <cstdio> #include <cstring> //#include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <str

tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树

P1716 - 上帝造题的七分钟 From Riatre    Normal (OI)总时限:50s    内存限制:128MB    代码长度限制:64KB 背景 Background 裸体就意味着身体. 描述 Description “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵.第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作.第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作.第

POJ 2155 二维线段树

POJ 2155  二维线段树 思路:二维线段树就是每个节点套一棵线段树的树. 刚开始因为题目是求A[I,J],然后在y查询那直接ans^=Map[i][j]的时候没看懂,后面自己把图画出来了才理解. 因为只有0和1,所以可以用异或来搞,而不需要每次都需要修改. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #incl