1. 程式人生 > >5312: 冒險 線段樹 復雜度分析

5312: 冒險 線段樹 復雜度分析

ext pla .com 國際 same png 卡常 .... BE

國際慣例的題面:
技術分享圖片
一看到這種維護序列的題,數據範圍分塊過不去,顯然線段樹了。
考慮位運算的性質,and相當於欽定一些位必須是0,or相當於欽定一些位必須是1,這都是一些區間賦值操作。
然而我們不可以按位確定,為什麽?因為當你確定了最高位之後,你需要在滿足高位的情況下求出低位,這相當於是一個取子集操作,單層的樹是不可做的。(樹套樹20層?恭喜你不如n^2暴力了)
於是去ORZ了英文題解,發現他是這樣分析的:
我們對每一個位上的操作把數分成兩類,有影響的和無影響的。因為操作對這兩種數不同,所以我們不能直接維護。
但是,顯然在一個操作之後,兩種不同的數會被變得相同!
於是,當我們操作到某一個區間,如果這個操作對區間內的所有數並不是全部相同,那麽我們遞歸下去做(也就是訪問多余節點)。因為操作後兩邊這些位的數會變得相同,而變相同的次數有限,所以復雜度是正確的。(表示原文一堆勢能分析不明覺厲)
然後就是怎麽判斷操作對某個區間是否相同的問題了。我們維護區間的and和和or和,顯然兩者的xor和就是這個區間存在不同的位。如果這些存在不同的位與本次操作會被欽定的位and起來不為0的話,就說明這次操作對這個區間的所有數並非完全相同,需要遞歸下去做。
另外,這題略卡常......
代碼:

技術分享圖片
 1 #pragma GCC optimize(2)
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cctype>
 5 const unsigned maxn=2e5+1e2,maxe=(maxn<<2)+5;
 6 const unsigned full = ( 1 << 21 ) - 1;
 7 
 8 unsigned in[maxn];
 9 struct SegmentTree {
10     unsigned andsu[maxe],orsu[maxe],lazyand[maxe],lazyor[maxe],mx[maxe];
11 #define lson(pos) (pos<<1) 12 #define rson(pos) (pos<<1|1) 13 inline void upgrade(unsigned pos) { 14 andsu[pos] = andsu[lson(pos)] & andsu[rson(pos)] , orsu[pos] = orsu[lson(pos)] | orsu[rson(pos)] , mx[pos] = std::max( mx[lson(pos)] , mx[rson(pos)] ); 15 }
16 inline void build(unsigned pos,unsigned ll,unsigned rr) { 17 lazyand[pos] = full; 18 if( ll == rr ) return void( andsu[pos] = orsu[pos] = mx[pos] = in[ll] ); 19 const unsigned mid = ( ll + rr ) >> 1; 20 build(lson(pos),ll,mid) , build(rson(pos),mid+1,rr) , upgrade(pos); 21 } 22 inline void apply(unsigned pos,const unsigned &x,const unsigned &tpe) { // tpe = 1 means and , tpe = 2 means or . 23 if( tpe == 1 ) andsu[pos] &= x , orsu[pos] &= x , lazyand[pos] &= x , lazyor[pos] &= x , mx[pos] &= x; 24 else if( tpe == 2 ) andsu[pos] |= x , orsu[pos] |= x , lazyor[pos] |= x , mx[pos] |= x; 25 } 26 inline void push(unsigned pos) { 27 if( lazyand[pos] != full ) apply(lson(pos),lazyand[pos],1) , apply(rson(pos),lazyand[pos],1) , lazyand[pos] = full; 28 if( lazyor ) apply(lson(pos),lazyor[pos],2) , apply(rson(pos),lazyor[pos],2) , lazyor[pos] = 0; 29 } 30 inline bool allsame(unsigned pos,const unsigned &x,const unsigned &tpe) { 31 unsigned dif = andsu[pos] ^ orsu[pos] , ref = ( tpe == 1 ? 0 : full ) ^ x; 32 return ! ( dif & ref ); 33 } 34 inline void update(unsigned pos,unsigned l,unsigned r,const unsigned &ll,const unsigned &rr,const unsigned &x,const unsigned &tpe) { 35 if( ll <= l && r <= rr && allsame(pos,x,tpe) ) return apply(pos,x,tpe); 36 push(pos); const unsigned mid = ( l + r ) >> 1; 37 if( rr <= mid ) update(lson(pos),l,mid,ll,rr,x,tpe); 38 else if( ll > mid ) update(rson(pos),mid+1,r,ll,rr,x,tpe); 39 else update(lson(pos),l,mid,ll,rr,x,tpe) , update(rson(pos),mid+1,r,ll,rr,x,tpe); 40 upgrade(pos); 41 } 42 inline unsigned query(unsigned pos,unsigned l,unsigned r,const unsigned &ll,const unsigned &rr) { 43 if( ll <= l && r <= rr ) return mx[pos]; 44 push(pos); const unsigned mid = ( l + r ) >> 1; 45 if( rr <= mid ) return query(lson(pos),l,mid,ll,rr); 46 else if( ll > mid ) return query(rson(pos),mid+1,r,ll,rr); 47 return std::max( query(lson(pos),l,mid,ll,rr) , query(rson(pos),mid+1,r,ll,rr) ); 48 } 49 }sgt; 50 51 inline char nextchar() { 52 static const unsigned BS = 1 << 22; 53 static unsigned char buf[BS],*st=buf+BS,*ed=st; 54 if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin); 55 return st == ed ? -1 : *st++; 56 } 57 inline unsigned getint() { 58 unsigned ret = 0 , ch; 59 while( !isdigit(ch=nextchar()) ); 60 do ret=ret*10+ch-0; while( isdigit(ch=nextchar()) ); 61 return ret; 62 } 63 64 int main() { 65 static unsigned n,m; 66 n = getint() , m = getint(); for(unsigned i=1;i<=n;in[i++]=getint()); 67 sgt.build(1,1,n); 68 for(unsigned i=1,o,l,r,x;i<=m;i++) o = getint() , l = getint() , r = getint() , o == 3 ? printf("%d\n",sgt.query(1,1,n,l,r)) : x = getint() , sgt.update(1,1,n,l,r,x,o); 69 return 0; 70 }
View Code


はらり はらり さやかな白よ
飄零的 飛散的 明亮的白色啊
夢の 終わる その場所で
在這裏 夢的終結之所
淡く 流れ わたしの戀を
淡淡地 流淌的 我的愛戀
こころ ふかく そめてゆく
深深地 染進心中

5312: 冒險 線段樹 復雜度分析