1. 程式人生 > >Codeforces 242E. XOR on Segment (二維線段樹 lazy操作 xor)

Codeforces 242E. XOR on Segment (二維線段樹 lazy操作 xor)

又是 維護 problem -- spa c++ push_back str 題目

題目鏈接:

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; }

Codeforces 242E. XOR on Segment (二維線段樹 lazy操作 xor)