您的位置:首页 > 其它

FZU 2105 Digits Count 区间更新

2015-07-20 18:00 309 查看
题意:有四个操作

1. l r v,对于[l,r]区间内的所有数都和v按位且(a[i]=a[i]&v)

2. l r v,对于[l,r]区间内的所有数都和v按位或(a[i]=a[i]|v)

3. l r v,对于[l,r]区间内的所有数都和v按位异或(a[i]=a[i]^v)

4. l r,对于[l,r]区间内的数求和

但是数据很小,所有的数和被操作数都是4位的,所以只需要统计每一位的1的个数就行。

但是需要注意的地方

且操作:如果对应位为0,那么就是区间赋值为0

或操作:如果对应位为1,那么就是区间赋值为1

异或操作:若对应位为1,那么区间内1的数量变为0的数量,区间内的1和0的数量互换

假设且操作和异或操作为op1

假设异或操作为op2

op1和op2的操作顺序需要考虑:

若当前节点为op1、子节点为op1,那么无意义,op1直接覆盖

若当前节点为op1、子节点为op2,op1直接覆盖

若当前节点为op2、子节点为op1,那么子节点op1的结果影响op2,所以先把子节点的op1推向子节点的子节点

若当前节点为op2、子节点为op2,这种情况有点复杂,其实画画图就可以得出,某个节点更新两遍之后值是不变的,所以设立一个标记,表示下一个节点是否需要更新,如果下一个节点需要被op2,那么值为1,下一个节点的值^1,以此传递下去。其实自己思考思考比较好。

代码:

//author: CHC
//First Edit Time:  2015-07-19 22:56
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <limits>
using namespace std;
typedef long long LL;
const int MAXN=1000000+1000;
const int INF = numeric_limits<int>::max();
const LL LL_INF= numeric_limits<LL>::max();
#define lson L,mid,rt<<1
#define rson mid+1,R,rt<<1|1
struct Tree {
int cnt[4];
int flag[4];
bool v[4];
}tr[MAXN<<2];
void pushup(int rt){
for(int i=0;i<4;i++){
tr[rt].cnt[i]=tr[rt<<1].cnt[i]+tr[rt<<1|1].cnt[i];
}
}
void pushdownA(int L,int R,int rt);
void pushdownB(int L,int R,int rt);
void pushdownC(int L,int R,int rt);
void pushdownA(int L,int R,int rt){
if(L==R)return ;
int mid=(L+R)>>1;
for(int i=0;i<4;i++){
if(tr[rt].flag[i]&1){
tr[rt<<1].cnt[i]=(mid-L+1);
tr[rt<<1|1].cnt[i]=(R-(mid+1)+1);
tr[rt<<1].flag[i]=tr[rt<<1|1].flag[i]=tr[rt].flag[i];
tr[rt].flag[i]=0;
tr[rt].v[i]=0;
}
}
}
void pushdownB(int L,int R,int rt){
if(L==R)return ;
//int mid=(L+R)>>1;
for(int i=0;i<4;i++){
if(tr[rt].flag[i]&2){
tr[rt<<1].cnt[i]=0;
tr[rt<<1|1].cnt[i]=0;
tr[rt<<1].flag[i]=tr[rt<<1|1].flag[i]=tr[rt].flag[i];
tr[rt].flag[i]=0;
tr[rt].v[i]=0;
}
}
}
void pushdownC(int L,int R,int rt){
int mid=(L+R)>>1;
for(int i=0;i<4;i++){
if(tr[rt].flag[i]&4){
if(tr[rt<<1].flag[i]&1)pushdownA(lson);
if(tr[rt<<1].flag[i]&2)pushdownB(lson);
if(tr[rt<<1|1].flag[i]&1)pushdownA(rson);
if(tr[rt<<1|1].flag[i]&2)pushdownB(rson);
if(tr[rt].v[i]){
tr[rt<<1].cnt[i]=mid-L+1-tr[rt<<1].cnt[i];
tr[rt<<1|1].cnt[i]=R-(mid+1)+1-tr[rt<<1|1].cnt[i];
tr[rt<<1].v[i]^=1;
tr[rt<<1|1].v[i]^=1;
}
tr[rt<<1].flag[i]=tr[rt<<1|1].flag[i]=tr[rt].flag[i];
tr[rt].flag[i]=0;
tr[rt].v[i]=0;
}
}
}
void pushdown(int L,int R,int rt){
if(L==R)return ;
pushdownA(L,R,rt);
pushdownB(L,R,rt);
pushdownC(L,R,rt);
}
int A[MAXN];
void build(int L,int R,int rt){
memset(&tr[rt],0,sizeof(Tree));
if(L==R){
for(int i=0;i<4;i++)
tr[rt].cnt[i]=(A[L]>>i)&1;
return ;
}
int mid=(L+R)>>1;
build(lson);build(rson);
pushup(rt);
}
void update(int L,int R,int rt,int l,int r,int flag,int pos){
pushdown(L,R,rt);
if(l<=L&&R<=r){
if(flag&1){
tr[rt].cnt[pos]=(R-L+1);
tr[rt].flag[pos]=flag;
}
if(flag&2){
tr[rt].cnt[pos]=0;
tr[rt].flag[pos]=flag;
}
if(flag&4){
tr[rt].cnt[pos]=(R-L+1)-tr[rt].cnt[pos];
tr[rt].flag[pos]=flag;
tr[rt].v[pos]=1;
}
return ;
}
int mid=(L+R)>>1;
if(l<=mid)update(lson,l,r,flag,pos);
if(r>mid)update(rson,l,r,flag,pos);
pushup(rt);
return ;
}
int query(int L,int R,int rt,int l,int r,int pos){
pushdown(L,R,rt);
if(l<=L&&R<=r)return tr[rt].cnt[pos];
int mid=(L+R)>>1,ans=0;
if(l<=mid)ans+=query(lson,l,r,pos);
if(r>mid)ans+=query(rson,l,r,pos);
pushup(rt);
return ans;
}
int main()
{
int t,n,m;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&A[i]);
build(1,n,1);
char strs[10];
for(int i=0,l,r,v;i<m;i++){
scanf(" %s",strs);
if(strs[0]=='S'){
scanf("%d%d",&l,&r);
++l;++r;
int ans=query(1,n,1,l,r,0)+query(1,n,1,l,r,1)*2+query(1,n,1,l,r,2)*4+query(1,n,1,l,r,3)*8;
printf("%d\n",ans);
}
if(strs[0]=='X'){
scanf("%d%d%d",&v,&l,&r);
++l;++r;
for(int i=0;i<4;i++){
if((v>>i)&1)update(1,n,1,l,r,4,i);
}
}
if(strs[0]=='O'){
scanf("%d%d%d",&v,&l,&r);
++l;++r;
for(int i=0;i<4;i++){
if((v>>i)&1)update(1,n,1,l,r,1,i);
}
}
if(strs[0]=='A'){
scanf("%d%d%d",&v,&l,&r);
++l;++r;
for(int i=0;i<4;i++){
if(((v>>i)&1)==0)update(1,n,1,l,r,2,i);
}
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树 区间更新