这道题是FZU 2105
一看就是区间信息的维护与查询问题,然后就是选择数据结构,简单分析下,树状数组与rmq都不能满足要求,于是乎我们就要用线段树了!(不想啊<_<)
一开始的想法是 寻找a&b+a&c与b+c之间的关系,想建立一个最普通的求和线段树,但是没有找到!(T_T)
然后突然间发现0<=a[i]<=15,于是分析得,对数列做多组运算后,有很多数值都会变得相同,像样例中最后A={6 6 6 7} 三个数都为6.
于是我们就可以将线段数维护数据设为连续区间内,数据是否完全相同。point[o]=-1,代表不同。point[o]=n,代表此区间内所有元素都为n。
于是我们就可以快速求和了.
下面是我的代码:
#include <cstdio>
const int maxn =1000010;
using namespace std;
int point[maxn*2];
int operators(int op,int opn,int num){
if(op==1) return opn#
if(op==2) return opn|num;
if(op==3) return opn^num;
}
int build (int o,int L,int R){
point[o]=-1;
if (L==R){
//printf("%d %d\n",L,R);
scanf("%d",&point[o]);
}
else {
int M=L+(R-L)/2;
build(o*2,L,M);
build(o*2+1,M+1,R);
if (point[o*2]!=-1&&point[o*2]==point[o*2+1]){
point[o]=point[o*2];
}
}
return 0;
}
int update(int o,int L,int R,int ql,int qr,int op,int opn){
int M=L+(R-L)/2;
if (ql<=L&&qr>=R&&point[o]>=0) point[o]=operators(op,opn,point[o]);
else {
if (L==R) return 0;
if (point[o]>=0) {
point[o*2+1]=point[o*2]=point[o];
point[o]=-1;
}
if (ql<=M) update(o*2,L,M,ql,qr,op,opn);
if (qr>M) update(o*2+1,M+1,R,ql,qr,op,opn);
if (point[o*2]!=-1&&point[o*2]==point[o*2+1]){
point[o]=point[o*2];
}
else point[o]=-1;
}
return 0;
}
long long sum;
int query(int o,int L,int R,int ql,int qr){
if (ql<=L&&qr>=R&&point[o]>=0) sum+=point[o]*(R-L+1);
else {
int M=L+(R-L)/2;
if (point[o]>=0) {
point[o*2+1]=point[o*2]=point[o];
point[o]=-1;
}
if (ql<=M) query(o*2,L,M,ql,qr);
if (qr>M) query(o*2+1,M+1,R,ql,qr);
if (point[o*2]!=-1&&point[o*2]==point[o*2+1]){
point[o]=point[o*2];
}
else point[o]=-1;
}
return 0;
}
int main (){
int n,m,T;scanf("%d",&T);
while (T--){
scanf("%d%d",&n,&m);
build(1,1,n);
char sss[5];
for (int i=0;i<m;i++){
scanf("%s",sss);
if (sss[0]=='S') {
int a,b;
scanf("%d%d",&a,&b);sum=0;
query(1,1,n,a+1,b+1);
printf("%I64d\n",sum);
}
if (sss[0]=='X') {
int opnn,a,b;
scanf("%d%d%d",&opnn,&a,&b);
update(1,1,n,a+1,b+1,3,opnn);
}
if (sss[0]=='O'){
int opnn,a,b;
scanf("%d%d%d",&opnn,&a,&b);
update(1,1,n,a+1,b+1,2,opnn);
}
if (sss[0]=='A'){
int opnn,a,b;
scanf("%d%d%d",&opnn,&a,&b);
update(1,1,n,a+1,b+1,1,opnn);
}
//for (int i=1;i<=8;i++) printf("%d \n",point[i]);
}
}
return 0;
}