• FZU-2105 Digits Count (两种标记成段更新)


    题目大意:给n个0~15之间的数,有3种更新操作,1种询问操作。3种更新操作是:1、让某个闭区间的所有数字与一个0~15之间的数字进行逻辑与运算;2、让某个闭区间的所有数字与一个0~15之间的数字进行逻辑或运算;3、让某个闭区间的所有数字与一个0~15之间的数字进行异或运算。一种询问操作是询问某个闭区间的所有数字之和。

    题目分析:所有的输入数字都是在0~15之间,可以二进制中的每一位建立线段树,建立四棵。3种更新操作实际上只有两种,即区间置位和区间反转。用两个懒惰标记,当进行区间置位更新的时候,要清除已经存在的反转标记,这样就能保证标记下传时两种标记下传的先后次序。

    代码如下:

    # include<iostream>
    # include<cstdio>
    # include<cstring>
    # include<algorithm>
    using namespace std;
    
    # define LL long long
    
    const int N=1000000;
    
    int n,m;
    int a[N+5];
    int tr[4][N*4+5];
    int lazy[4][N*4+5];
    int lazy_xor[4][N*4+5];
    char com[5];
    
    void pushDown(int id,int rt,int l,int r)
    {
    	int mid=l+(r-l)/2;
    	if(lazy[id][rt]!=-1){
    		lazy_xor[id][rt<<1]=lazy_xor[id][rt<<1|1]=0;
    		lazy[id][rt<<1]=lazy[id][rt<<1|1]=lazy[id][rt];
    		tr[id][rt<<1]=lazy[id][rt]*(mid-l+1);
    		tr[id][rt<<1|1]=lazy[id][rt]*(r-mid);
    		lazy[id][rt]=-1;
    	}
    	int &q=lazy_xor[id][rt];
    	if(q==1){
    		lazy_xor[id][rt<<1]^=1;
    		lazy_xor[id][rt<<1|1]^=1;
    		tr[id][rt<<1]=mid-l+1-tr[id][rt<<1];
    		tr[id][rt<<1|1]=r-mid-tr[id][rt<<1|1];
    		q=0;
    	}
    }
    
    void pushUp(int id,int rt)
    {
    	tr[id][rt]=tr[id][rt<<1]+tr[id][rt<<1|1];
    }
    
    void build(int id,int rt,int l,int r)
    {
    	lazy[id][rt]=-1;
    	lazy_xor[id][rt]=0;
    	if(l==r){
    		if((a[r]&(1<<id))>0) tr[id][rt]=1;
    		else tr[id][rt]=0;
    	}else{
    		int mid=l+(r-l)/2;
    		build(id,rt<<1,l,mid);
    		build(id,rt<<1|1,mid+1,r);
    		pushUp(id,rt);
    	}
    }
    
    void update(int id,int rt,int l,int r,int L,int R,int x)
    {
    	if(L<=l&&r<=R){
    		if(x==2){
    			if(lazy[id][rt]!=-1) lazy[id][rt]^=1;
    			else lazy_xor[id][rt]^=1;
    			tr[id][rt]=(r-l+1)-tr[id][rt];
    		}else{
    			lazy[id][rt]=x;
    			lazy_xor[id][rt]=0;
    			tr[id][rt]=x*(r-l+1);
    		}
    	}else{
    		pushDown(id,rt,l,r);
    		int mid=l+(r-l)/2;
    		if(L<=mid) update(id,rt<<1,l,mid,L,R,x);
    		if(R>mid) update(id,rt<<1|1,mid+1,r,L,R,x);
    		pushUp(id,rt);
    	}
    }
    
    LL query(int id,int rt,int l,int r,int L,int R)
    {
    	if(L<=l&&r<=R) return tr[id][rt];
    	pushDown(id,rt,l,r);
    	int mid=l+(r-l)/2;
    	LL res=0;
    	if(L<=mid) res+=query(id,rt<<1,l,mid,L,R);
    	if(R>mid) res+=query(id,rt<<1|1,mid+1,r,L,R);
    	return res;
    }
    
    int main()
    {
    	//freopen("in.txt","r",stdin);
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d",&n,&m);
    		for(int i=0;i<n;++i) scanf("%d",a+i);
    		for(int i=0;i<4;++i)
    			build(i,1,0,n-1);
    		int o,b,c;
    		while(m--)
    		{
    			scanf("%s",com);
    			if(com[0]=='S'){
    				scanf("%d%d",&b,&c);
    				int ans=0;
    				for(int i=0;i<4;++i){
    					ans+=query(i,1,0,n-1,b,c)*(1<<i);
    				}
    				printf("%d
    ",ans);
    			}else{
    				scanf("%d%d%d",&o,&b,&c);
    				if(com[0]=='X'){
    					for(int i=0;i<4;++i) if(o&(1<<i))
    						update(i,1,0,n-1,b,c,2);
    				}else if(com[0]=='O'){
    					for(int i=0;i<4;++i) if(o&(1<<i))
    						update(i,1,0,n-1,b,c,1);
    				}else if(com[0]=='A'){
    					for(int i=0;i<4;++i) if(!(o&(1<<i)))
    						update(i,1,0,n-1,b,c,0);
    				}
    			}
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    怎样在caffe中添加layer以及caffe中triplet loss layer的实现
    【java】为数组全部元素赋同样的值 以及 数组之间的复制
    POJ 2386 Lake Counting 搜索题解
    android中实现内容搜索
    JNI之——在cmd命令行下编译执行C/C++源文件
    怎样编写高效android代码
    http headers
    matlab 工具函数、matlab toolbox(工具箱)
    数列收敛与数列极限
    数列收敛与数列极限
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/5552416.html
Copyright © 2020-2023  润新知