今天集训队打比赛的一道题,很明显是个线段树,我们队照着lrj蓝书敲了一通,机智的将修改值和加和改成了位运算:|=
但是好像哪里出了点小问题,就是不对,赛后又水了一遍,竟然过了。。。发现还是lrj的书好啊,市面上的模板一点也不好用,连区间修改都没有 。
等集训完了要静心好好系统的学习一下线段树 。 多看多刷lrj的书 。
细节参见代码:
?
#includeusing namespace std; const int maxn = 1000000 + 5; int n,m,_sum,v,a,b,y11,y22,c,setv[maxn * 3],sumv[maxn * 3]; char cmd[5]; void pushdown(int o) { int lc = o*2 , rc = o*2 + 1; if(setv[o] >= 0) { setv[lc] = setv[rc] = setv[o] ; setv[o] = -1; } } void maintain(int o,int L,int R) { int lc = o*2 , rc = o*2 + 1; sumv[o] = 0; if(R > L) { sumv[o] = sumv[lc] | sumv[rc]; } if(setv[o] >= 0) { sumv[o] = setv[o]; return ; } return ; } void update(int o,int L,int R) { int lc = o*2 , rc = o*2 + 1; if(y11 <= L && y22 >= R) setv[o] = v; else { pushdown(o); int m = L + (R-L)/2; if(y11 <= m) update(lc,L,m); else maintain(lc,L,m); if(y22 > m) update(rc,m+1,R); else maintain(rc,m+1,R); } maintain(o,L,R); } void query(int o,int L,int R) { if(setv[o] >= 0) { _sum |= setv[o]; } else if(y11 <= L && y22 >= R) { _sum |= sumv[o]; } else { int m = L + (R-L)/2; if(y11 <= m) query(o*2 , L , m) ; if(y22 > m) query(o*2 + 1, m+1, R); } } int main() { while(~scanf(%d%d,&n,&m)) { if( !n && !m ) return 0; v = 2; y11 = 1; y22 = n; update(1,1,n); while(m--) { scanf(%s,cmd); if(cmd[0] == 'P') { scanf(%d%d%d,&y11,&y22,&c); v = (1<<(c-1)); update(1,1,n); } else { scanf(%d%d,&y11,&y22); _sum = 0; query(1,1,n); bool ok = true; for(int i=0;i<30;i++) if(_sum & (1< ?