<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      勢能線段樹

      勢能線段樹包括了吉司機線段樹。思想就是正常線段樹可能遇到難 pushup 的情況,我們直接暴力遞歸,然后根據勢能分析說明這個暴力復雜度是均攤可接受的。

      【勢能線段樹】

      【例一】

      CF438D The Child and Sequence

      題意:

      支持三種操作。

      1. 單點修改。

      2. 區間對給定數取模。

      3. 區間求和。

      \(n,q\le 10^5\),時限 4s.


      注意到一個事實:當 \(x\ge p\)\(x\bmod p\le x/2\)。也就是如果不計修改,每個數有效取模次數只有 \(O(\log V)\) 次。

      對線段樹每個結點記錄區間最大值和區間和。單點修改很好做。區間取模時,如果當前結點最大值 \(<mod\),就沒必要修改可以直接返回了;如果最大值 \(\ge mod\),暴力遞歸左右兒子取模,然后 pushup 回來。


      復雜度分析。在勢能線段樹的復雜度分析時,我們只需要說明 "暴力遞歸" 的復雜度不會太高即可。因為其他部分和普通線段樹是嚴格 \(O(\log n)\) 的。

      對于結點 \(u:[l,r]\),定義其勢能 \(\phi(u)=\sum_{i=l}^r(\log a_i)\)

      1. 當暴力遞歸時,說明 \(u\) 代表的區間內有至少一個數會折半,也就是 \(\log a_i\) 會減少 \(1\)

        所有結點的勢能不增。同時所有包含被取模元素的區間勢能都會減少。

      2. 單點修改最多只會讓一條鏈上所有線段樹結點的勢能增加 \(\log V\),也就是總共增加 \(\log n\log V\)。所以最多增加 \(O(q\log n\log V)\)

      3. 初始勢能是 \(O(n\log V\log n)\) 的。因為一層勢能是 \(O(n\log V)\) 的,一共 \(\log n\) 層。

      綜上所述,每次遞歸總勢能減少 \(1\),初始勢能 \(O(n\log V\log n)\),單點修改最多增加 \(O(q\log V\log n)\),因此總復雜度 \(O((n+q)\log V\log n)\)

      typedef pair<long long, long long> pii;
      
      pii operator+(pii a, pii b) {
      	return make_pair(a.first + b.first, max(a.second, b.second));
      }
      pii operator%(pii a, long long b) {
      	return make_pair(a.first % b, a.second % b);
      }
      
      struct SegmentTree {
      	long long sz;
      	vector<pair<long long, long long> > val;
      	pii ide1 = make_pair(0ll, 0ll);
      	
      	void pushup(long long x) {
      		val[x] = val[x * 2] + val[x * 2 + 1];
      	}
      	void build(long long x, long long lx, long long rx, vector<long long> &a) {
      		if (lx + 1 == rx) {
      			val[x] = (lx <= a.size() ? make_pair(a[lx - 1], a[lx - 1]) : ide1);
      			return ;
      		}
      		long long m = (lx + rx) / 2;
      		build(x * 2, lx, m, a);
      		build(x * 2 + 1, m, rx, a);
      		pushup(x);
      	}
      	SegmentTree(){}
      	SegmentTree(vector<long long> &a) {
      		for (sz = 1; sz < a.size(); sz *= 2);
      		val.assign(2 * sz, ide1);
      		build(1, 1, sz + 1, a);
      	}
      	void mdf_mod(long long x, long long lx, long long rx, long long l, long long r, long long p) {
      //		cout << x << ' ' << lx << ' ' << rx << ' ' << l << ' ' << r << ' ' << p << endl;
      		if (val[x].second < p)
      			return ;
      		if (lx + 1 == rx) {
      //			cout << '!';
      			val[x] = val[x] % p;
      //			cout << val[x].first << ' ' << val[x].second << endl;
      			return ;
      		}
      		long long m = (lx + rx) / 2;
      		if (l < m)
      			mdf_mod(x * 2, lx, m, l, r, p);
      		if (r > m)
      			mdf_mod(x * 2 + 1, m, rx, l, r, p);
      		pushup(x);
      	}
      	void mdf(long long x, long long lx, long long rx, long long p, long long v) {
      		if (lx + 1 == rx) {
      			val[x] = make_pair(v, v);
      			return ;
      		}
      		long long m = (lx + rx) / 2;
      		if (p < m)
      			mdf(x * 2, lx, m, p, v);
      		else
      			mdf(x * 2 + 1, m, rx, p, v);
      		pushup(x);
      	}
      	pii qry(long long x, long long lx, long long rx, long long l, long long r) {
      		if (l <= lx && rx <= r)
      			return val[x];
      		if (l >= rx || lx >= r)
      			return ide1;
      		long long m = (lx + rx) / 2;
      		return qry(x * 2, lx, m, l, r) + qry(x * 2 + 1, m, rx, l, r); 
      	}
      } st;
      

      【例二】

      gym103107A And RMQ

      題意:

      支持三種操作。

      1. 區間求最大值。

      2. 單點修改。

      3. 區間對給定數按位與。

      \(n,q\le 4\times 10^5\),時限 3s.


      勢能線段樹最重要的就是想明白什么情況可以剪枝

      顯然,假設我們要對區間與上 \(v\),如果 \(v\)\(0\) 的位已經全都是 \(0\) 了,可以剪枝。換句話說,設區間的或等于 \(x\),如果 (x | v) == v 就可以剪枝。

      對結點記錄區間 \(\max\) 和區間按位或的值。前兩個正常做,在區間按位與時,如果 (valor[x] | v) == v 就退出。


      復雜度分析。

      一個結點的勢能定義為 \(\sum_{i=l}^r \operatorname{popcount}(a_i)\),顯然總勢能 \(O(n\log n\log V)\),單點修改至多增加 \(O(\log n\log V)\)

      同時每次暴力遞歸總勢能至少 \(-1\),按位與說明 \(1\) 的個數不增,也就是任何點勢能不會增加。總共 \(O((n+q)\log n\log V)\)

      int n, m;
      int a[N];
      
      int mx[N << 2], valor[N << 2];
      
      void pushup(int x) {
      	mx[x] = max(mx[x * 2], mx[x * 2 + 1]);
      	valor[x] = valor[x * 2] | valor[x * 2 + 1];
      }
      void mdf(int x, int lx, int rx, int l, int r, int v) {
      	if ((v | valor[x]) == v)
      		return ;
      	if (l >= rx || lx >= r)
      		return ;
      	if (lx + 1 == rx) {
      		valor[x] &= v;
      		mx[x] = valor[x];
      		return ;
      	}
      	int m = (lx + rx) / 2;
      	mdf(x * 2, lx, m, l, r, v);
      	mdf(x * 2 + 1, m, rx, l, r, v);
      	pushup(x);
      }
      void mdf(int x, int lx, int rx, int p, int v) {
      	if (lx + 1 == rx) {
      		mx[x] = valor[x] = v;
      		return ;
      	}
      	int m = (lx + rx) / 2;
      	if (p < m)
      		mdf(x * 2, lx, m, p, v);
      	else
      		mdf(x * 2 + 1, m, rx, p, v);
      	pushup(x);
      }
      int qry(int x, int lx, int rx, int l, int r) {
      	if (l <= lx && rx <= r)
      		return mx[x];
      	if (l >= rx || lx >= r)
      		return -1;
      	int m = (lx + rx) / 2;
      	return max(qry(x * 2, lx, m, l, r), qry(x * 2 + 1, m, rx, l, r));
      }
      void build(int x, int lx, int rx) {
      	if (lx + 1 == rx) {
      		mx[x] = valor[x] = a[lx];
      		return ;
      	}
      	int m = (lx + rx) / 2;
      	build(x * 2, lx, m);
      	build(x * 2 + 1, m, rx);
      	pushup(x);
      }
      

      【例三】

      CF444C DZY Loves Colors

      思路:當整個區間的顏色都相同時,可以直接打懶標記區間加。

      對結點 \(u\) 保存:

      1. \(clr\),若 \(clr=0\) 表示區間顏色個數 \(\ge 2\);否則表示區間顏色都是 \(clr\)

      2. \(tag\),區間加的懶標記。我們認為 \(tag\) 已經對 \(sum\) 作用了,也就是只作用真子孫。

      3. \(sum\),區間權值和。


      復雜度分析。區別在于有區間修改,需要分析會不會有勢能增加

      定義結點 \(u\) 勢能為 \(\phi(u)=[clr_u=0]\)。顯然因為線段樹結點 \(O(n)\) 個,初始勢能是 \(O(n)\) 的。接下來考慮暴力遞歸對勢能的影響。

      每次暴力遞歸,說明要修改的區間完全包含 \(u\),同時 \(u\) 內顏色個數 \(\ge 2\)。考慮所有結點的勢能變化:

      1. \(u\) 肯定減少,從 \(\ge 2\) 種顏色變成賦值的顏色。

      2. \(u\) 的子孫們勢能不增。因為全部賦值成 \(1\) 種顏色了。

      3. \(u\) 的祖先、子孫的結點勢能不變,因為在線段樹修改過程中都不會訪問到它們。

      4. 剩下是 \(u\) 的真祖先。考慮所有 \(u\) 的祖先們,即線段樹在正常拆區間時訪問到的結點。

        如果粗略來看,每個被訪問的結點都可能勢能 \(+1\),線段樹每一層有 \(2\) 個區間被訪問,一共正常訪問 \(O(\log n)\) 個結點,這么說一次操作增加 \(O(\log^2 n)\) 的勢能,總復雜度是 \(O(m\log^3n)\) 嗎?

        其實并不是,因為 \(u\) 內的顏色個數都 \(\ge 2\) 了,所以 \(u\) 的祖先顏色個數也 \(\ge 2\),所以祖先的勢能本就是 \(1\),不可能增加了,反而可能減少。

      綜上所述,暴力遞歸勢能必定減少。而勢能初值為 \(O(n)\) 的,所以復雜度是 \(O((n+m)\log n)\)

      【例四】

      冒險

      題意:

      支持三個操作。

      1. 區間按位與。

      2. 區間按位或。

      3. 求區間最大值。

      \(n,q\le 2\times 10^5\)\(a_i<2^{20}\)


      這題麻煩一些,有兩個剪枝:

      1. 類似例一,對結點記錄 valor, valand,如果發現修改沒用就直接返回。

      2. 如果修改對于整個區間的作用是一樣的,用懶標記修改。

      第一條很好理解,第二條是什么意思呢?

      例如我們要與上 11000011,如果 \(u\) 中所有數中間四位都相同(全都是 ??ABCD?? 的形式),相當于區間整體減 ABCD00。或是同理的。

      所以我們對結點額外記錄 \(tag\):區間整體加上 \(tag\) 的懶標記。在我們發現第二條剪枝生效的時候,比如我們要對區間整體 \(+v\),我們就讓 tag, valor, valand\(+v\)。注意 valor, valand 在這里也是可以加減的,因為我們要么是讓一些 \(1\) 整體變 \(0\),要么是讓一些 \(0\) 整體變 \(1\),沒有進位退位的情況。顯然是可以直接放到 valor, valand 身上的。

      具體判定:valor ^ valand\(0\) 的位是整個區間都一樣的。


      復雜度分析。這題涉及到勢能增加

      valor ^ valand\(1\) 的位簡稱為 "有分歧的"。對結點 \(u\) 定義其勢能 \(\phi(u)\)\(u\) 區間有分歧的位數。初始總勢能是 \(O(n\log V)\) 的。

      首先強行遞歸肯定會使得 \(\phi(u)\) 至少減一。然后對于每個正常訪問到的結點,勢能最多增加 \(O(\log V)\),所以一次操作勢能增加量為 \(O(\log n\log V)\)。總增加 \(O(q\log n\log V)\)

      因此總復雜度是 \(O(q\log n\log V)\) 的。

      void tagadd(int u, int v){
      	tagAnd[u] += v; tagOr[u] += v; mx[u] += v; lazy[u] += v;
      }
      	
      void pushUp(int i){
          tagAnd[i] = tagAnd[lc] & tagAnd[rc];
          tagOr[i] = tagOr[lc] | tagOr[rc];
          mx[i] = max(mx[lc], mx[rc]);
      }
      
      void pushDown(int i){
      	tagadd(lc, lazy[i]);
      	tagadd(rc, lazy[i]);
      	lazy[i] = 0;
      }
      
      void rangeAnd(int i,int L,int R,int l,int r,int x){
          if ((tagOr[i] & x) == tagOr[i]) return;
          int check = tagAnd[i]^tagOr[i]; // check 表示相等的位置。 
          if (l <= L && r >= R && ((check | x) == x))  // x中為0的地方,check也為0. 
      		tagadd(i, (tagAnd[i]&x)-tagAnd[i]);  
      	else{    
      	    int mid=(L+R)>>1;
          	pushDown(i);
          	if(l<=mid) rangeAnd(lc,L,mid,l,r,x);
          	if(r>mid) rangeAnd(rc,mid+1,R,l,r,x);
          	pushUp(i);
          }
      }
      
      void rangeOr(int i,int L,int R,int l,int r,int x){
          if ((tagAnd[i] | x) == tagAnd[i]) return;
          int check = tagAnd[i]^tagOr[i]; // check 表示相等的位置。 
          if (l <= L && r >= R && ((check & x) == 0))  // x中為1的地方,check也為0. 
      		tagadd(i, (tagAnd[i]|x)-tagAnd[i]); 
      	else{    
      	    int mid=(L+R)>>1;
          	pushDown(i);
          	if(l<=mid) rangeOr(lc,L,mid,l,r,x);
          	if(r>mid) rangeOr(rc,mid+1,R,l,r,x);
          	pushUp(i);
          }
      }
      
      int queryMax(int i,int L,int R,int l,int r){
          if(l<=L&&r>=R) return mx[i];
          int mid=(L+R)>>1,res=-1;
          pushDown(i);
          if(l<=mid) res=max(res,queryMax(lc,L,mid,l,r));
          if(r>mid) res=max(res,queryMax(rc,mid+1,R,l,r));
          return res;
      }
      
      void build(int i,int L,int R){
          if(L==R){
          	int a; scanf("%d", &a);
          	mx[i] = tagAnd[i] = tagOr[i] = a; lazy[i]=0;  
          }
          else{
          	int mid=(L+R)>>1;
          	build(lc,L,mid); build(rc,mid+1,R); 
      		pushUp(i);
          }
      }
      

      【例五】

      UOJ228 Rikka with sequence

      支持三個操作。

      1. 區間求和。

      2. 區間加。

      3. 區間開方下取整。

      \(n,m,a_i\le 10^5\)


      考慮怎么剪枝。記錄區間 \(mn\)\(mx\)

      1. \(mn=mx\),等價于區間減法。

      2. \(mn+1=mx\),則要么等價于區間減法,要么等價于區間賦值。

      對于 \(mx-mn>1\) 就暴力遞歸。


      復雜度分析。這題的勢能分析采用對數的形式,是個勢能分析的 trick

      這里的定義比較特別。記 \(\phi(u)=\log(mx-mn)\)(若 \(mx-mn\)\(\phi(u)=0\))。

      1. 分析區間開方。

        如果暴力遞歸了,說明 \(mx-mn\ge 2\)。我們在這個條件下求證 \(u\) 勢能至少 \(-1\)

        \([\sqrt{mn}]=C,[\sqrt{mx}]=C+\Delta\)。轉證 \(mx-mn\ge 2\Delta\)

        \[ \begin{aligned} mx-mn-2\Delta&\ge (C+\Delta)^2-((C+1)^2-1)-2\Delta\\ &= 2C\Delta+\Delta^2-2C-2\Delta\\ &=\Delta(2C+\Delta)-2(C+\Delta) \end{aligned} \]

        \(\Delta \ge 2\) 時,顯然成立。而當 \(\Delta=0/1\) 時,\(\phi(u')=0\) 顯然變小了。

      posted @ 2025-02-20 22:47  FLY_lai  閱讀(223)  評論(2)    收藏  舉報
      主站蜘蛛池模板: 国语精品国内自产视频| 欧美人与动牲猛交A欧美精品| 久久婷婷五月综合色国产免费观看| 中文字幕人妻丝袜美腿乱| 亚洲a∨国产av综合av| 日本一区三区高清视频| 黄色大全免费看国产精品| 亚洲一区二区三区激情视频 | 91精品人妻中文字幕色| 丝袜美腿亚洲综合在线观看视频| 成人午夜在线观看刺激| 免费人妻无码不卡中文18禁| 亚洲另类丝袜综合网| 午夜高清国产拍精品福利| 2021亚洲va在线va天堂va国产| 国产又色又爽又黄的网站免费| 人妻少妇精品视频三区二区| 免费国精产品wnw2544| 国产精品天天看天天狠| 午夜免费无码福利视频麻豆| 国产一区二区不卡91| av在线播放日韩亚洲欧| 亚洲色大成网站WWW国产| 亚洲色欲色欱WWW在线| 久久国内精品一国内精品| 成码无人AV片在线电影网站 | 激情综合网激情综合网五月| 樱花草视频www日本韩国| 宜君县| 日韩少妇人妻vs中文字幕 | 亚洲成在人线AV品善网好看| 天堂在线最新版在线天堂| 亚洲国产韩国欧美在线| 樱桃视频影院在线播放| 深夜av在线免费观看| 亚洲精品美女久久久久99| 热久久美女精品天天吊色| 鲁丝一区二区三区免费| 久久亚洲精品无码播放| 日韩av在线一区二区三区| 精品黄色av一区二区三区|