FZU 2105 線段樹

題意:明顯的線段樹,對一個區間進行操作,操作包括與,或,異或,求和四種,也就是三種操作(均爲位運算),一個詢問。不過每個數字都很小,[0,16],這很奇怪,而且位運算每位之間是獨立的,所以可以用四個線段樹分別維護每一位,求和的時候求四次,加起來就可以。


對於與操作:如果某一位爲1,操作之後不產生變化,所以只考慮0的情況,0的時候全變爲0,相當於覆蓋

對於或操作:如果某一位爲0,不產生變化,只考慮1,相當於覆蓋爲1

對於異或:0,不產生變化,1相當於每一位均取反


所以整理之後有兩種操作,一種是區間覆蓋,一種是區間取反,這兩種操作明顯不是一類的,所以需要用兩個延遲標記,不過兩個延遲標記又產生了順序的問題,參考題解後發現是這樣處理的:當對一個區間進行操作的時候,需要先看看有沒有其他的操作(兩種都需要考慮),然後採取不同的操作。也就是一個區間的延遲標記不能同時有標記(如果與順序無關的話就不用這麼麻煩了),這樣就木有問題了=。=


代碼:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 1000000+5;
bool XOR[4][maxn<<2];
int OR[4][maxn<<2];
int sum[4][maxn<<2];
int nn[maxn];
void pushup(int id,int rt){
	sum[id][rt] = (sum[id][rt<<1] + sum[id][rt<<1|1]);
}
void build(int id,int l,int r,int rt){
	XOR[id][rt] = 0;
	OR[id][rt] = -1;
	if(l == r){
		bool ii = (nn[l]&(1<<id))!=0?1:0;
		sum[id][rt] = ii;
		//cout<<id<<' '<<ii<<endl;
		return ;
	}
	int m = (l + r) >> 1;
	build(id,lson);
	build(id,rson);
	pushup(id,rt);
}
void pushdown(int id,int rt,int m){
	if(OR[id][rt] != -1){
		OR[id][rt<<1] = OR[id][rt<<1|1] = OR[id][rt];
		XOR[id][rt<<1] = XOR[id][rt<<1|1] = 0;
		sum[id][rt<<1] = OR[id][rt<<1] * (m - (m>>1));
		sum[id][rt<<1|1] = OR[id][rt<<1|1] * (m>>1);
		OR[id][rt] = -1;
	}
	if(XOR[id][rt] == 1){
		if(OR[id][rt<<1] != -1)OR[id][rt<<1] ^= 1;
		else XOR[id][rt<<1] ^= 1;
		if(OR[id][rt<<1|1] != -1)OR[id][rt<<1|1] ^= 1;
		else XOR[id][rt<<1|1] ^= 1;
		sum[id][rt<<1] = (m - (m>>1)) - sum[id][rt<<1];
		sum[id][rt<<1|1] = (m>>1) - sum[id][rt<<1|1];
		XOR[id][rt] = 0;
	}
}
void update_OR(int id,int L,int R,int c,int l,int r,int rt){
	if(L <= l&&r <= R){
		XOR[id][rt] = 0;
		OR[id][rt] = c;
		sum[id][rt] = c*(r - l  + 1);
		return ;
	}
	pushdown(id,rt,r-l+1);
	int m = (l + r) >>1;
	if(L <= m)update_OR(id,L,R,c,lson);
	if(m < R)update_OR(id,L,R,c,rson);
	pushup(id,rt);
}
void update_XOR(int id,int L,int R,int l,int r,int rt){
	if(L <= l&&r <= R){
		if(OR[id][rt] != -1){
			OR[id][rt] ^= 1;
		}
		else {
			XOR[id][rt] ^= 1;
		}
		sum[id][rt] = (r - l + 1) - sum[id][rt];
		return ;
	}
	pushdown(id,rt,r-l+1);
	int m = (l + r)>>1;
	if(L <= m)update_XOR(id,L,R,lson);
	if(m < R)update_XOR(id,L,R,rson);
	pushup(id,rt);
}
int query(int id,int L,int R,int l,int r,int rt){
	if (L <= l && r <= R) {
		return sum[id][rt];
	}
	pushdown(id,rt , r - l + 1);
	int m = (l + r) >> 1;
	int ret = 0;
	if (L <= m) ret += query(id,L , R , lson);
	if (m < R) ret += query(id,L , R , rson);
	return ret;
}
int main(){
	//freopen("in.txt","r",stdin);
	int T;
	scanf("%d",&T);
	while(T --){
		int n,m;
		scanf("%d%d",&n,&m);
		for(int i = 1;i <= n;i ++)scanf("%d",&nn[i]);
		for(int i = 0;i < 4;i ++){
			build(i,1,n,1);//cout<<i<<"aaaaaaaaaa";
		}
		char s[20];
		int l,r,op;
		while(m --){
			scanf("%s",s);
			if(s[0] == 'S'){
				scanf("%d%d",&l,&r);l++;r++;
				int ans = 0;
				for(int i = 3;i >= 0;i --){
					ans += (1<<i)*query(i,l,r,1,n,1);
				}
				printf("%d\n",ans);
			}
			else if(s[0] == 'X'){
				scanf("%d%d%d",&op,&l,&r);l++;r++;
				for(int i = 0;i < 4;i ++){
					if(op&(1<<i))
						update_XOR(i,l,r,1,n,1);
				}
			}
			else if(s[0] == 'A'){
				scanf("%d%d%d",&op,&l,&r);l++;r++;
				for(int i = 0;i < 4;i ++){
					if(!(op&(1<<i)))
						update_OR(i,l,r,0,1,n,1);
				}
			}
			else if(s[0] == 'O'){
				scanf("%d%d%d",&op,&l,&r);l++;r++;
				for(int i = 0;i < 4;i ++){
					if(op&(1<<i))
						update_OR(i,l,r,1,1,n,1);
				}
			}
		}
	}
	return 0;
}


發佈了140 篇原創文章 · 獲贊 5 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章