zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    asp.net导出数据到execl并保存到本地 不需要调用Office组件
    动态创建DataTable,GridView创建多表头,表头跨行或跨列合并,创建计算列及列内容自适应等
    Oracle内置SQL函数收集整理大全
    无比强大的GridView,表头固定,表体有滚动条可滚动
    很不错的asp.net文件上传类c# 搜索文件 移动文件 删除文件等
    【备用】非常不错的ASP操作数据库类,支持多数据库MSSQL,ACCESS,ORACLE,MYSQL等
    Asp.Net读取Execl常见问题收集
    经常用到的交叉表问题,一般用动态SQL能生成动态列
    C# asp.net中常见的字符串处理函数及数字格式化
    比较两个DataTable中不同的记录,且合并两个DataTable的列显示,有图
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/5552416.html
Copyright © 2011-2022 走看看