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<<"]\n"
#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\n",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] == '\n')) c++;
		if(c >= sz) return false;
		int len = 0;
		while(c < sz && buf[c] != ' ' && buf[c] != '\n') s[len++] = buf[c] , c++;
		s[len]=0;
		return true;
	}
}
using namespace IO;

//打开方式:

int x;
read(x);
 
      

  

 
 
      

  

 

 

转载于:https://www.cnblogs.com/HDMaxfun/p/5793956.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。
ACM线段模板C ```c #include<bits/stdc++.h> using namespace std; const int N=1e5+5;//数组开大一点 int n,m; int a[N]; struct node{ int l,r;//左右端点 int sum,lazy;//区间和和懒标记 }t[N*4]; void up(int p){//向上更新 t[p].sum=t[p<<1].sum+t[p<<1|1].sum; } void down(int p){//向下更新 if(t[p].lazy){ t[p<<1].lazy+=t[p].lazy; t[p<<1|1].lazy+=t[p].lazy; t[p<<1].sum+=t[p].lazy*(t[p<<1].r-t[p<<1].l+1); t[p<<1|1].sum+=t[p].lazy*(t[p<<1|1].r-t[p<<1|1].l+1); t[p].lazy=0; } } void build(int p,int l,int r){//建 t[p].l=l,t[p].r=r; if(l==r){ t[p].sum=a[l]; return; } int mid=(l+r)/2; build(p<<1,l,mid); build(p<<1|1,mid+1,r); up(p); } void change(int p,int l,int r,int k){//单点修改 if(t[p].l==t[p].r){ t[p].sum=k; return; } down(p); int mid=(t[p].l+t[p].r)/2; if(r<=mid) change(p<<1,l,r,k); else if(l>mid) change(p<<1|1,l,r,k); else{ change(p<<1,l,mid,k); change(p<<1|1,mid+1,r,k); } up(p); } void add(int p,int l,int r,int k){//区间修改 if(t[p].l>=l&&t[p].r<=r){ t[p].sum+=k*(t[p].r-t[p].l+1); t[p].lazy+=k; return; } down(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid) add(p<<1,l,r,k); if(r>mid) add(p<<1|1,l,r,k); up(p); } int query(int p,int l,int r){//区间查询 if(t[p].l>=l&&t[p].r<=r) return t[p].sum; down(p); int mid=(t[p].l+t[p].r)/2,ans=0; if(l<=mid) ans+=query(p<<1,l,r); if(r>mid) ans+=query(p<<1|1,l,r); return ans; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; build(1,1,n); for(int i=1;i<=m;i++){ int opt,x,y,k; cin>>opt; if(opt==1){ cin>>x>>y>>k; add(1,x,y,k); } if(opt==2){ cin>>x>>y; cout<<query(1,x,y)<<endl; } if(opt==3){ cin>>x>>k; change(1,x,x,k); } } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值