FZU 2105 位运算 (线段树)

106 篇文章 0 订阅
44 篇文章 0 订阅

由于各项数据范围都是0-15,所有把一个数拆成四位二进制数来维护,对应三种操作分别不同分别跑循环操作一下就可以。

更新lazy的时候会比较麻烦。

要注意如果你默认lazy操作为and, or, xor对应的lazy值分别为0,1,1(因为只有这些值会对结果产生影响),对xor对应的值直接异或的话,需要把异或后为0的lazy标记直接抹去。


大概就是这样了,然后不要整个数组都memset会省去一半的时间。


代码:

#include <iostream>
#include <stdio.h>
#include <cstring>
#define lson o<<1
#define rson o<<1|1
#define MID int mid=(l+r)>>1;
#define LL long long
using namespace std;
const int maxn=1e6+5;
int val[maxn<<2][4];
int lazy[maxn<<2][4];
int lazyop[maxn<<2][4];
int a[maxn];
int num[5];
void cal(int x)
{
    int i=0;
    for(int j=0; j<4; j++)
    {
        num[i++]=x%2;
        x/=2;
    }
    return;
}

int sum(int o)
{
    int res=0, x=1;
    for(int i=0; i<4; i++)
    {
        res+=x*val[o][i];
        x*=2;
    }
    return res;
}
void build(int o, int l, int r)
{
    if(l==r)
    {
        cal(a[l]);
        for(int i=0; i<4; i++)val[o][i]+=num[i];
        return;
    }
    MID;
    build(lson, l, mid);
    build(rson, mid+1, r);
    for(int i=0; i<4; i++)val[o][i]=val[lson][i]+val[rson][i];
    return;
}

void push_down(int o, int l, int r)
{
    MID;
    for(int i=0; i<4; i++)
    {
        /* 
        if(r==10)
        {
            printf("%d %d %d\n", l, r, lazyop[o][i]);
        }
        */
        switch (lazyop[o][i])
        {
        case 1:
        {
            val[lson][i]=0;
            val[rson][i]=0;
            lazyop[lson][i]=1, lazy[lson][i]=0;
            lazyop[rson][i]=1, lazy[rson][i]=0;

            break;
        }
        case 2:
        {
            val[lson][i]=mid-l+1;
            val[rson][i]=r-(mid+1)+1;
            lazyop[lson][i]=2, lazy[lson][i]=1;
            lazyop[rson][i]=2, lazy[rson][i]=1;
            break;
        }
        case 3:
        {
            val[lson][i]=(mid-l+1)-val[lson][i];
            val[rson][i]=(r-(mid+1)+1)-val[rson][i];
            lazy[lson][i]^=1;
            if(lazyop[lson][i]==1)lazyop[lson][i]=2;
            else if(lazyop[lson][i]==2)lazyop[lson][i]=1;
            else if(lazyop[lson][i]==0)lazyop[lson][i]=3, lazy[lson][i]=1;
            if(lazyop[lson][i]==3 && lazy[lson][i]==0)lazyop[lson][i]=0;

            lazy[rson][i]^=1;
            if(lazyop[rson][i]==1)lazyop[rson][i]=2;
            else if(lazyop[rson][i]==2)lazyop[rson][i]=1;
            else if(lazyop[rson][i]==0)lazyop[rson][i]=3, lazy[rson][i]=1;
            if(lazyop[rson][i]==3 && lazy[rson][i]==0)lazyop[rson][i]=0;
            break;
        }
        }
            lazyop[o][i]=0;
            lazy[o][i]=0;
    }
    
   // printf("\n");
    return;
}

void update(int o, int l, int r, int ll, int rr, int op)
{
    if(ll<=l && r<=rr)
    {
        if(op==1){for(int i=0; i<4; i++)if(num[i]==0){val[o][i]=0;lazy[o][i]=0;lazyop[o][i]=1;   }   }
        if(op==2){for(int i=0; i<4; i++)if(num[i]==1){val[o][i]=r-l+1;lazy[o][i]=1;lazyop[o][i]=2;   }   }
        if(op==3){
            for(int i=0; i<4; i++)
            {
                 if(num[i]==1)
                 {
                     val[o][i]=r-l+1-val[o][i];
                     if(lazyop[o][i]==1)lazyop[o][i]=2, lazy[o][i]=1;
                     else if(lazyop[o][i]==2)lazyop[o][i]=1, lazy[o][i]=0;
                     else if(lazyop[o][i]==3)lazy[o][i]^=num[i], lazyop[o][i]=lazy[o][i]?3:0;
                     else lazy[o][i]=1, lazyop[o][i]=3;
                     
                 }   
            }
        
        }
        return;
    }
    push_down(o, l, r);
    MID;
    if(ll<=mid)update(lson, l, mid, ll, rr, op);
    if(rr>mid)update(rson, mid+1, r, ll, rr, op);
    for(int i=0; i<4; i++)val[o][i]=val[lson][i]+val[rson][i];
    return;
}

int query(int o, int l, int r, int ll, int rr)
{
    if(ll<=l && r<=rr)
    {
        return sum(o);       
    }
    push_down(o, l, r);
    MID;
    int res=0;
    if(ll<=mid)res+=query(lson, l, mid, ll, rr);
    if(rr>mid)res+=query(rson, mid+1, r, ll, rr);
    for(int i=0; i<4; i++)val[o][i]=val[lson][i]+val[rson][i];
    return res;
}


int main()
{
  //  freopen("C:\\Users\\johsnow\\Desktop\\data.in", "r", stdin);
  //  freopen("C:\\Users\\johsnow\\Desktop\\ans.out", "w", stdout);
    int t, n, m, x, i, j, l, r;
    char str[10];
    cin>>t;
    while(t--)
    {
            scanf("%d%d", &n, &m);
            for(i=0; i<=4*n; i++)
            {
                memset(lazy[i], 0, sizeof lazy[i]);
                memset(lazyop[i], 0, sizeof lazyop[i]);
                memset(val[i], 0, sizeof val[i]);
            }

            for(i=1; i<=n; i++)
            {
                scanf("%d", &a[i]);
            }
            build(1, 1, n);
            while(m--)
            {
            scanf("%s", str);
            if(str[0]=='S')
            {
                scanf("%d%d", &l, &r);
                l++, r++;
                printf("%d\n", query(1, 1, n, l, r));
            }
            else if(str[0]=='O')
            {
                scanf("%d%d%d", &x, &l, &r);
                l++, r++;
                cal(x);
                update(1, 1, n, l, r, 2);
            }
            else if(str[0]=='X')
            {
                scanf("%d%d%d", &x, &l, &r);
                l++, r++;
                cal(x);
                update(1, 1, n, l, r, 3);
            }
            else if(str[0]=='A')
            {
                scanf("%d%d%d", &x, &l, &r);
                l++, r++;
                cal(x);
                update(1, 1, n, l, r, 1);
            }
            }


    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值