FZU 2105 Digits Count 区间更新

题意:有四个操作
1. l r v,对于[l,r]区间内的所有数都和v按位且(a[i]=a[i]&v)
2. l r v,对于[l,r]区间内的所有数都和v按位或(a[i]=a[i]|v)
3. l r v,对于[l,r]区间内的所有数都和v按位异或(a[i]=a[i]^v)
4. l r,对于[l,r]区间内的数求和
但是数据很小,所有的数和被操作数都是4位的,所以只需要统计每一位的1的个数就行。
但是需要注意的地方

且操作:如果对应位为0,那么就是区间赋值为0
或操作:如果对应位为1,那么就是区间赋值为1
异或操作:若对应位为1,那么区间内1的数量变为0的数量,区间内的1和0的数量互换

假设且操作和异或操作为op1
假设异或操作为op2
op1和op2的操作顺序需要考虑:

若当前节点为op1、子节点为op1,那么无意义,op1直接覆盖
若当前节点为op1、子节点为op2,op1直接覆盖
若当前节点为op2、子节点为op1,那么子节点op1的结果影响op2,所以先把子节点的op1推向子节点的子节点
若当前节点为op2、子节点为op2,这种情况有点复杂,其实画画图就可以得出,某个节点更新两遍之后值是不变的,所以设立一个标记,表示下一个节点是否需要更新,如果下一个节点需要被op2,那么值为1,下一个节点的值^1,以此传递下去。其实自己思考思考比较好。

代码:

//author: CHC
//First Edit Time:  2015-07-19 22:56
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <limits>
using namespace std;
typedef long long LL;
const int MAXN=1000000+1000;
const int INF = numeric_limits<int>::max();
const LL LL_INF= numeric_limits<LL>::max();
#define lson L,mid,rt<<1
#define rson mid+1,R,rt<<1|1
struct Tree {
    int cnt[4];
    int flag[4];
    bool v[4];
}tr[MAXN<<2];
void pushup(int rt){
    for(int i=0;i<4;i++){
        tr[rt].cnt[i]=tr[rt<<1].cnt[i]+tr[rt<<1|1].cnt[i];
    }
}
void pushdownA(int L,int R,int rt);
void pushdownB(int L,int R,int rt);
void pushdownC(int L,int R,int rt);
void pushdownA(int L,int R,int rt){
    if(L==R)return ;
    int mid=(L+R)>>1;
    for(int i=0;i<4;i++){
        if(tr[rt].flag[i]&1){
            tr[rt<<1].cnt[i]=(mid-L+1);
            tr[rt<<1|1].cnt[i]=(R-(mid+1)+1);
            tr[rt<<1].flag[i]=tr[rt<<1|1].flag[i]=tr[rt].flag[i];
            tr[rt].flag[i]=0;
            tr[rt].v[i]=0;
        }
    }
}
void pushdownB(int L,int R,int rt){
    if(L==R)return ;
    //int mid=(L+R)>>1;
    for(int i=0;i<4;i++){
        if(tr[rt].flag[i]&2){
            tr[rt<<1].cnt[i]=0;
            tr[rt<<1|1].cnt[i]=0;
            tr[rt<<1].flag[i]=tr[rt<<1|1].flag[i]=tr[rt].flag[i];
            tr[rt].flag[i]=0;
            tr[rt].v[i]=0;
        }
    }
}
void pushdownC(int L,int R,int rt){
    int mid=(L+R)>>1;
    for(int i=0;i<4;i++){
        if(tr[rt].flag[i]&4){
            if(tr[rt<<1].flag[i]&1)pushdownA(lson);
            if(tr[rt<<1].flag[i]&2)pushdownB(lson);
            if(tr[rt<<1|1].flag[i]&1)pushdownA(rson);
            if(tr[rt<<1|1].flag[i]&2)pushdownB(rson);
            if(tr[rt].v[i]){
                tr[rt<<1].cnt[i]=mid-L+1-tr[rt<<1].cnt[i];
                tr[rt<<1|1].cnt[i]=R-(mid+1)+1-tr[rt<<1|1].cnt[i];
                tr[rt<<1].v[i]^=1;
                tr[rt<<1|1].v[i]^=1;
            }
            tr[rt<<1].flag[i]=tr[rt<<1|1].flag[i]=tr[rt].flag[i];
            tr[rt].flag[i]=0;
            tr[rt].v[i]=0;
        }
    }
}
void pushdown(int L,int R,int rt){
    if(L==R)return ;
    pushdownA(L,R,rt);
    pushdownB(L,R,rt);
    pushdownC(L,R,rt);
}
int A[MAXN];
void build(int L,int R,int rt){
    memset(&tr[rt],0,sizeof(Tree));
    if(L==R){
        for(int i=0;i<4;i++)
            tr[rt].cnt[i]=(A[L]>>i)&1;
        return ;
    }
    int mid=(L+R)>>1;
    build(lson);build(rson);
    pushup(rt);
}
void update(int L,int R,int rt,int l,int r,int flag,int pos){
    pushdown(L,R,rt);
    if(l<=L&&R<=r){
        if(flag&1){
            tr[rt].cnt[pos]=(R-L+1);
            tr[rt].flag[pos]=flag;
        }
        if(flag&2){
            tr[rt].cnt[pos]=0;
            tr[rt].flag[pos]=flag;
        }
        if(flag&4){
            tr[rt].cnt[pos]=(R-L+1)-tr[rt].cnt[pos];
            tr[rt].flag[pos]=flag;
            tr[rt].v[pos]=1;
        }
        return ;
    }
    int mid=(L+R)>>1;
    if(l<=mid)update(lson,l,r,flag,pos);
    if(r>mid)update(rson,l,r,flag,pos);
    pushup(rt);
    return ;
}
int query(int L,int R,int rt,int l,int r,int pos){
    pushdown(L,R,rt);
    if(l<=L&&R<=r)return tr[rt].cnt[pos];
    int mid=(L+R)>>1,ans=0;
    if(l<=mid)ans+=query(lson,l,r,pos);
    if(r>mid)ans+=query(rson,l,r,pos);
    pushup(rt);
    return ans;
}
int main()
{
    int t,n,m;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&A[i]);
        build(1,n,1);
        char strs[10];
        for(int i=0,l,r,v;i<m;i++){
            scanf(" %s",strs);
            if(strs[0]=='S'){
                scanf("%d%d",&l,&r);
                ++l;++r;
                int ans=query(1,n,1,l,r,0)+query(1,n,1,l,r,1)*2+query(1,n,1,l,r,2)*4+query(1,n,1,l,r,3)*8;
                printf("%d\n",ans);
            }
            if(strs[0]=='X'){
                scanf("%d%d%d",&v,&l,&r);
                ++l;++r;
                for(int i=0;i<4;i++){
                    if((v>>i)&1)update(1,n,1,l,r,4,i);
                }
            }
            if(strs[0]=='O'){
                scanf("%d%d%d",&v,&l,&r);
                ++l;++r;
                for(int i=0;i<4;i++){
                    if((v>>i)&1)update(1,n,1,l,r,1,i);
                }
            }
            if(strs[0]=='A'){
                scanf("%d%d%d",&v,&l,&r);
                ++l;++r;
                for(int i=0;i<4;i++){
                    if(((v>>i)&1)==0)update(1,n,1,l,r,2,i);
                }
            }
        }
    }
    return 0;
}

你可能感兴趣的:(线段树,区间更新)