您的位置:首页 > 其它

FZU 2105 线段树

2015-06-10 16:24 375 查看
题意:明显的线段树,对一个区间进行操作,操作包括与,或,异或,求和四种,也就是三种操作(均为位运算),一个询问。不过每个数字都很小,[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: