fzu2105 线段树分位成段更新

来源:互联网 发布:网络教育怎么报名啊 编辑:程序博客网 时间:2024/06/05 03:07

由于数字很小,只有4位有效,所以维护4棵线段树,这样就可以叠加处理各个操作

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>int tree[4][6000005];int a[1000005];int b[4][1000005];int vis[4][6000005];int n,m;void build(int left,int right,int root){if(left==right){for(int i=0;i<=3;i++)tree[i][root]=b[i][left];return ;}int mid=(left+right)/2;build(left,mid,root<<1);build(mid+1,right,root<<1|1);for(int i=0;i<=3;i++)tree[i][root]=tree[i][root<<1]+tree[i][root<<1|1];}void update(int left,int right,int root){int mid;mid=(left+right)/2;for(int i=0;i<=3;i++){if(vis[i][root]==1){tree[i][root<<1]=mid-left+1;tree[i][root<<1|1]=right-(mid+1)+1;vis[i][root<<1]=vis[i][root<<1|1]=1;}else if(vis[i][root]==-1){tree[i][root<<1]=0;    tree[i][root<<1|1]=0;vis[i][root<<1]=vis[i][root<<1|1]=-1;}else if(vis[i][root]==2){tree[i][root<<1]=mid-left+1-tree[i][root<<1];tree[i][root<<1|1]=right-(mid+1)+1-tree[i][root<<1|1];if(vis[i][root<<1]==1)vis[i][root<<1]=-1;else if(vis[i][root<<1]==-1)vis[i][root<<1]=1;else if(vis[i][root<<1]==2)vis[i][root<<1]=0;else vis[i][root<<1]=2;if(vis[i][root<<1|1]==1)vis[i][root<<1|1]=-1;else if(vis[i][root<<1|1]==-1)vis[i][root<<1|1]=1;else if(vis[i][root<<1|1]==2)vis[i][root<<1|1]=0;else vis[i][root<<1|1]=2;}vis[i][root]=0;}}void and(int left,int right,int root,int l,int r,int temp){if( (left==l) && (right==r)){for(int i=0;i<=3;i++){if(((1<<i)&temp)==0){tree[i][root]=0;vis[i][root]=-1;}}return;}update(left,right,root);int mid=(left+right)/2;if(r<=mid)and(left,mid,root<<1,l,r,temp);else if(l>=mid+1)and(mid+1,right,root<<1|1,l,r,temp);else{and(left,mid,root<<1,l,mid,temp);and(mid+1,right,root<<1|1,mid+1,r,temp);}for(int i=0;i<=3;i++)tree[i][root]=tree[i][root<<1]+tree[i][root<<1|1];}void or(int left,int right,int root,int l,int r,int temp){if( (left==l) && (right==r)){for(int i=0;i<=3;i++){if(((1<<i)&temp)!=0){tree[i][root]=right-left+1;vis[i][root]=1;}}return;}update(left,right,root);int mid=(left+right)/2;if(r<=mid)or(left,mid,root<<1,l,r,temp);else if(l>=mid+1)or(mid+1,right,root<<1|1,l,r,temp);else{or(left,mid,root<<1,l,mid,temp);or(mid+1,right,root<<1|1,mid+1,r,temp);}for(int i=0;i<=3;i++)tree[i][root]=tree[i][root<<1]+tree[i][root<<1|1];}void xor(int left,int right,int root,int l,int r,int temp){if( (left==l) && (right==r)){for(int i=0;i<=3;i++){if(((1<<i)&temp)!=0){tree[i][root]=right-left+1-tree[i][root];if(vis[i][root]==1)vis[i][root]=-1;else if(vis[i][root]==-1)vis[i][root]=1;else if(vis[i][root]==2)vis[i][root]=0;else vis[i][root]=2;}}return;}update(left,right,root);int mid=(left+right)/2;if(r<=mid)xor(left,mid,root<<1,l,r,temp);else if(l>=mid+1)xor(mid+1,right,root<<1|1,l,r,temp);else{xor(left,mid,root<<1,l,mid,temp);xor(mid+1,right,root<<1|1,mid+1,r,temp);}for(int i=0;i<=3;i++)tree[i][root]=tree[i][root<<1]+tree[i][root<<1|1];}int find(int left,int right,int root,int l,int r){if( (left==l) && (right==r)){return tree[0][root]+tree[1][root]*2+tree[2][root]*4+tree[3][root]*8;}    update(left,right,root);int mid=(left+right)/2;if(r<=mid)return find(left,mid,root<<1,l,r);else if(l>=mid+1)return find(mid+1,right,root<<1|1,l,r);elsereturn find(left,mid,root<<1,l,mid)+find(mid+1,right,root<<1|1,mid+1,r);}int main(){int T;scanf("%d",&T);char ts[10];while(T--){int i,j;int ta,tb,tc;scanf("%d%d",&n,&m);memset(b,0,sizeof(b));memset(vis,0,sizeof(vis));for(i=1;i<=n;i++){scanf("%d",&a[i]);for(j=0;j<=3;j++)if(a[i]&(1<<j))b[j][i]++;}build(1,n,1);while(m--){scanf("%s",ts);if(ts[0]=='S'){scanf("%d%d",&ta,&tb);ta++;tb++;printf("%d\n",find(1,n,1,ta,tb));}else if(ts[0]=='A'){scanf("%d%d%d",&tc,&ta,&tb);ta++;tb++;and(1,n,1,ta,tb,tc);}else if(ts[0]=='X'){scanf("%d%d%d",&tc,&ta,&tb);ta++;tb++;xor(1,n,1,ta,tb,tc);}else{scanf("%d%d%d",&tc,&ta,&tb);ta++;tb++;or(1,n,1,ta,tb,tc);}}}return 0;}


0 0