zoukankan      html  css  js  c++  java
  • ACM: FZU 2105 Digits Count

     FZU 2105  Digits Count
    Time Limit:10000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u

    Description

    Given N integers A={A[0],A[1],...,A[N-1]}. Here we have some operations:

    Operation 1: AND opn L R

    Here opn, L and R are integers.

    For L≤i≤R, we do A[i]=A[i] AND opn (here "AND" is bitwise operation).

    Operation 2: OR opn L R

    Here opn, L and R are integers.

    For L≤i≤R, we do A[i]=A[i] OR opn (here "OR" is bitwise operation).

    Operation 3: XOR opn L R

    Here opn, L and R are integers.

    For L≤i≤R, we do A[i]=A[i] XOR opn (here "XOR" is bitwise operation).

    Operation 4: SUM L R

    We want to know the result of A[L]+A[L+1]+...+A[R].

    Now can you solve this easy problem?

    Input

    The first line of the input contains an integer T, indicating the number of test cases. (T≤100)

    Then T cases, for any case, the first line has two integers n and m (1≤n≤1,000,000, 1≤m≤100,000), indicating the number of elements in A and the number of operations.

    Then one line follows n integers A[0], A[1], ..., A[n-1] (0≤A[i]<16,0≤i<n).

    Then m lines, each line must be one of the 4 operations above. (0≤opn≤15)

    Output

    For each test case and for each "SUM" operation, please output the result with a single line.

    Sample Input

    1
    4 4
    1 2 4 7
    SUM 0 2
    XOR 5 0 0
    OR 6 0 3
    SUM 0 2
    

    Sample Output

    7
    18
    

    Hint

    A = [1 2 4 7]

    SUM 0 2, result=1+2+4=7;

    XOR 5 0 0, A=[4 2 4 7];

    OR 6 0 3, A=[6 6 6 7];

    SUM 0 2, result=6+6+6=18.

    /*/
    题意:
    给出一组数,然后有4种操作。
    
    AND opn l r   对 l~r 段的数与 opn 进行&运算;
    
    OR opn l r 对 l~r 段的数与 opn 进行|运算;
    
    XOR opn l r 对 l~r 段的数与 opn 进行^运算;
    
    SUMl r 对 l~r 段的数求和,并输出。
    
    很明显的线段树,可是我还是太年轻。一开始以为只是一棵裸树,结果写到一半,发现不能对求和的数再进行与或非的运算,也不知道我哪里来的勇气,想到,既然不能对和去运算,不如把lazy全压下去。。。MDZZ。。。
    
    后来,队友提示我可以用二进制来存数,然后与或非的情况也就变得特别简单了。
    
    然后就用关于二进制的线段树来写了这个,思路一开始是很混乱的,不过写到后面还是被  >>  和 <<  坑了好久,还是修行不精啊。。。
    
    A了但是运行时间还是比较久。
    
    最后集训队队长发了个福利,读入优化,速度爆炸了,又是我的代码运行速度第一(233333)。
    
    AC代码:
    /*/
    #include"algorithm"
    #include"iostream"
    #include"cstring"
    #include"cstdlib"
    #include"cstdio"
    #include"string"
    #include"vector"
    #include"stack"
    #include"queue"
    #include"cmath"
    #include"map"
    using namespace std;
    typedef long long LL ;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1 	
    #define FK(x) cout<<"["<<x<<"]
    "
    #define memset(x,y) memset(x,y,sizeof(x))
    #define memcpy(x,y) memcpy(x,y,sizeof(x))
    #define smallfor(T)  for(int i=0 ;i<T ;i++)
    #define bigfor(T)  for(int qq=1;qq<= T ;qq++)
    
    const int MX =1111111;
    const int INF=0x3f3f3f3f;
    int sum[MX<<2][4],lazy[MX<<2][4];
    void PushUp(int rt,int i) {
    	sum[rt][i]=sum[rt<<1][i]+sum[rt<<1|1][i];
    }
    
    void PushDown(int rt,int m,int i) {
    	if(lazy[rt][i]==0) {     //如果进行了AND操作,并且该位为0 清空下面子树。 
    		lazy[rt<<1][i]=0;
    		lazy[rt<<1|1][i]=0;
    		sum[rt<<1][i]=sum[rt<<1|1][i]=0;
    	}
    	if(lazy[rt][i]==1) {     //如果进行了OR 操作,并且该位为1 填满下面子树。 
    		lazy[rt<<1][i]=1;
    		lazy[rt<<1|1][i]=1;
    		sum[rt<<1][i]=m-(m>>1);
    		sum[rt<<1|1][i]=m>>1;
    	}
    	if(lazy[rt][i]==2) {	 //如果进行了XOR操作 
    		if(lazy[rt<<1][i]==INF) { //如果没有进行过任何操作,标记为XOR操作 
    			lazy[rt<<1][i]=2;
    			sum[rt<<1][i]=m-(m>>1)-sum[rt<<1][i];
    		} else if(lazy[rt<<1][i]==2) {  //如果进行过XOR操作,a^b^b==a 恢复操作内容。 
    			lazy[rt<<1][i]=INF;
    			sum[rt<<1][i]=m-(m>>1)-sum[rt<<1][i];
    		} else {				  //如果进行了操作并且不是XOR操作 将该操作再取XOR操作 
    			lazy[rt<<1][i]^=1;
    			if(lazy[rt<<1][i]==0) sum[rt<<1][i]=0;
    			else  sum[rt<<1][i]=m-(m>>1);
    		}						  
    //							 另一棵子树用同样的方法处理
    				
    		if(lazy[rt<<1|1][i]==INF) {
    			lazy[rt<<1|1][i]=2;
    			sum[rt<<1|1][i]=(m>>1)-sum[rt<<1|1][i];
    		} else if(lazy[rt<<1|1][i]==2) {
    			lazy[rt<<1|1][i]=INF;
    			sum[rt<<1|1][i]=(m>>1)-sum[rt<<1|1][i];
    		} else {
    			lazy[rt<<1|1][i]^=1;
    			if(lazy[rt<<1|1][i]==0) sum[rt<<1|1][i]=0;
    			else sum[rt<<1|1][i]=(m>>1);
    		}
    	}
    	lazy[rt][i]=INF; //标记lazy为空
    }
    
    void Build(int l,int r,int rt) {
    	for(int i=0; i<4; i++) lazy[rt][i]=INF; //清空懒惰标记
    	if(r==l) {
    		int temp;
    		scanf("%d",&temp);
    //		FK("temp=="<<temp);
    		for(int i=0; i<4; i++) {
    			sum[rt][i]=(bool)(temp&(1<<i));//【这里一定要取(bool)否则得到的值不会是1,而是比 1大的数】
    //			该题目的方法是用sum保存每个位上值的总数,再改变为10进制,求和。 
    //			把数按照二进制保存在4个位上面 
    //			FK(sum[rt][i]);
    		}
    		return;
    	}
    	int m=(r+l)>>1;
    	Build(lson);
    	Build(rson);
    	for(int i=0; i<4; i++) PushUp(rt,i);
    }
    
    void UpData(int L,int R,int v,int i,int l,int r,int rt) {
    	if(r<=R&&L<=l) {
    		switch(v) {
    			case 0:
    				sum[rt][i]=0,lazy[rt][i]=v;
    				//如果是进行AND操作,并且是0,清空和。 
    				break;
    			case 1:
    				sum[rt][i]=r-l+1,lazy[rt][i]=v;
    				//如果是进行OR 操作,并且是1,填满和。 
    				break;
    			case 2:
    				sum[rt][i]=r-l+1-sum[rt][i];
    				if(lazy[rt][i]==2) lazy[rt][i]=INF;
    				else if(lazy[rt][i]==INF) lazy[rt][i]=2;
    				else lazy[rt][i]^=1;
    				break;
    			default:
    				break;
    		}
    		return ;
    	}
    	PushDown(rt,r-l+1,i);
    	int m=(r+l)>>1;
    	if(L<=m)UpData(L,R,v,i,lson);
    	if(R>m) UpData(L,R,v,i,rson);
    	PushUp(rt,i);
    }
    
    int Query(int L,int R,int i,int l,int r,int rt) {
    	if(L<=l&&r<=R) {
    		return sum[rt][i];
    //		返回这个数该位的和。 
    	}
    	int m=(r+l)>>1;
    	int sum=0;
    	PushDown(rt,r-l+1,i);
    	if(L<=m)sum+=Query(L,R,i,lson);
    	if(R>m) sum+=Query(L,R,i,rson);
    	return sum;
    }
    
    int main() {
    	int T;
    	scanf("%d",&T);
    	bigfor(T) {
    		int n,m;
    		scanf("%d%d",&n,&m);
    		char op[5];
    		Build(0,n-1,1);
    //		FK("Build Success!");
    		for(int i=0; i<m; i++) {
    			scanf("%s",op);
    			if(op[0]=='S') {
    				int l,r;
    				int ans=0;
    				scanf("%d%d",&l,&r);
    				for(int j=0; j<4; j++) ans+=Query(l,r,j,0,n-1,1)<<j;
    //				将每一位的数字和用10进制进位后相加。 
    				printf("%d
    ",ans);
    			} else {
    				int opn,l,r;
    				char v;
    				scanf("%d%d%d",&opn,&l,&r);
    				if(op[0]=='A') {  //AND为&如果某位上为 1 那么值不变 否则全变为0;【区间覆盖】
    					for(int j=0; j<4; j++) {
    						int x=opn&(1<<j);
    //						FK("j=="<<j<<"  x=="<<x);
    						if(!x)UpData(l,r,0,j,0,n-1,1);
    					}
    				}
    				if(op[0]=='O') {  //OR 为|如果某位上为 0 那么值不变 否则全变为1;【区间覆盖】
    					for(int j=0; j<4; j++) {
    						int x=opn&(1<<j);
    //						FK("j=="<<j<<"  x=="<<x);
    						if(x)UpData(l,r,1,j,0,n-1,1);
    					}
    				}
    				if(op[0]=='X') {  //XOR为^如果某位上为 0 那么值不变 否则0->1,1->0【区间更新】
    					for(int j=0; j<4; j++) {
    						int x=opn&(1<<j);
    //						FK("j=="<<j<<"  x=="<<x);
    						if(x)UpData(l,r,2,j,0,n-1,1);
    					}
    				}
    			}
    		}
    	}
    	return 0;
    }
    
    
    

        

    //下面是快速读入的福利【只适用于读入比较多的题目,适用于题目原本复杂度为O(n),但是自己的代码估计会是O(nlog(n)),这个优化的作用就会比较明显。】

    //下面就是黑科技:

    namespace IO {
    	const int MT = 5e7; //1e711000kb
    	char buf[MT];
    	int c, sz;
    	void begin() {
    		c = 0;
    		sz = fread(buf, 1, MT, stdin);
    	}
    	inline bool read(int &t) {
    		while(c < sz && buf[c] != '-' && (buf[c] < '0' || buf[c] > '9')) c++;
    		if(c >= sz) return false;
    		bool flag = 0;
    		if( buf[c] == '-')flag = 1, c++;
    		for(t = 0; c < sz && '0' <= buf[c] && buf[c] <='9'; c++) t = t * 10 + buf[c] - '0';
    		if(flag) t = -t;
    		return true;
    	} inline bool read(char s[]) {
    		while(c < sz && (buf[c] == ' ' || buf[c] == '
    ')) c++;
    		if(c >= sz) return false;
    		int len = 0;
    		while(c < sz && buf[c] != ' ' && buf[c] != '
    ') s[len++] = buf[c] , c++;
    		s[len]=0;
    		return true;
    	}
    }
    using namespace IO;
    
    //打开方式:
    
    int x;
    read(x);
    
    
    

      

     
    
    

      

     
  • 相关阅读:
    webpack学习笔记五
    webpack的学习使用四
    判断数组B是否为数组A的子集
    html5标签知多少
    图代文时隐藏文字的兼容实现
    负margin的移位参考线
    font-size 兼容问题
    IE6读取不到样式文件bug
    一个重构眼中的“项目管理”
    唯物 VS 唯心
  • 原文地址:https://www.cnblogs.com/HDMaxfun/p/5793956.html
Copyright © 2011-2022 走看看