日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P2572 [SCOI2010]序列操作

發布時間:2024/4/17 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P2572 [SCOI2010]序列操作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

對自己 & \(RNG\) : 驕兵必敗
\(lpl\)加油!

P2572 [SCOI2010]序列操作

題目描述
lxhgww最近收到了一個01序列,序列里面包含了n個數,這些數要么是0,要么是1,現在對于這個序列有五種變換操作和詢問操作:

0 a b 把[a, b]區間內的所有數全變成0

1 a b 把[a, b]區間內的所有數全變成1

2 a b 把[a,b]區間內的所有數全部取反,也就是說把所有的0變成1,把所有的1變成0

3 a b 詢問[a, b]區間內總共有多少個1

4 a b 詢問[a, b]區間內最多有多少個連續的1

對于每一種詢問操作,lxhgww都需要給出回答,聰明的程序員們,你們能幫助他嗎?


錯誤日志: 內容較多且重要, 將寫在下方加粗


Solution

線段樹, 需要維護以下信息:

  • \(sum\) 區間 \(1\) 的個數
  • \(max[0/1]\) 區間內 \(0/1\) 最長連續子段
  • \(lmax[0/1]\) 包含區間左端點最長 \(0/1\) 子段
  • \(rmax[0/1]\) 包含區間右端點最長 \(0/1\) 子段
  • 鑒于有區間操作, 這里還需要兩個標記:

  • \(lazy = {-1, 0, 1}\)\(-1\) 表示無狀態, 為 \(0/1\) 表示區間全部賦值為 \(0/1\)
  • \(rev = {0, 1}\) 區間是否翻轉

  • 需要維護的元素較多, 先講 \(pushup\)
    區間和直接相加即可
    包含左端點的連續子段有兩種情況:

  • 直接繼承左區間的 \(lmax\)
  • 當左區間全滿 / 全空時, 左端點可以跨越, 加上右區間的部分
  • 右區間更新同理

    對于區間最長連續子段, 有以下三種情況

  • 直接繼承左區間的較大值
  • 直接繼承右區間的較大值
  • 左區間的含右端點最長子段 + 右區間含左端點最長子段, 即最長部分跨越區間分割線
  • 以上需要分 \(0/1\) 討論, 程序中直接兩層循環搞定


    然后到了難點 \(pushdown\)
    我一個需要沖省隊的選手竟然直到現在才注意到這點很慘啊
    在線段樹 \(pushdown\) 操作中, 我們需要明確兩件事:

  • 標記的優先級
    2. 下放某一標記是否會對子節點的其他類型標記有所影響
  • 這里重點討論第二點(第一點區間全體賦值優先級肯定高于翻轉, 所以優先拆區間賦值標記, 拆標記時需要將翻轉標記清空)
    在拆解一個標記時, 我們不僅需要明確將此標記下放到子節點, 同類型的標記應該如何改變, 而更應明確拆解此標記會對 不同類型的標記有何種影響
    明確同類型的影響是一般不會出問題的, 如將區間加標記下放時, 子節點的區間加標記累加上這個值

    以本題為例:
    將區間賦值標記拆解時, 不僅需要將子區間賦值標記更新為此值, 還需要將子節點翻轉標記清空(不過這個貌似影響不大, 拆賦值標記時會將翻轉標記清空的)
    將區間翻轉標記拆解時, 需要分兩種情況考慮此標記下推對子區間 賦值標記 和 翻轉標記造成的影響
    考慮到賦值標記的優先級大于翻轉標記, 在有賦值標記的情況下, 直接翻轉賦值標記
    其余情況翻轉標記異或等于1


    其余見代碼 雖然很長但用心弄懂會對線段樹有一個很深刻的理解

    這樣完備地考慮所有情況是一個 \(OI\) 選手的基本素養


    嗯就這樣, \(RNG\) 別喪氣, 你們是最棒的; \(S8\)\(lpl\) 加油!

    Code

    #include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<algorithm> #include<climits> #define LL long long #define REP(i, x, y) for(int i = (x);i <= (y);i++) using namespace std; int RD(){int out = 0,flag = 1;char c = getchar();while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}return flag * out;} const int maxn = 200019; int num, na; int v[maxn]; #define lid (id << 1) #define rid (id << 1) | 1 //int max(int a, int b){return a > b ? a : b;}//聽說手寫快? struct seg_tree{int l, r;int sum;int lazy;//-1.NULL 0.全為0 1.全為1int rev;int max[2], lmax[2], rmax[2];}tree[maxn << 2]; void pushup(int id){tree[id].sum = tree[lid].sum + tree[rid].sum;REP(i, 0, 1){tree[id].lmax[i] = tree[lid].lmax[i];if(i == 1 && tree[lid].sum == tree[lid].r - tree[lid].l + 1)//左區間全滿tree[id].lmax[i] += tree[rid].lmax[i];//可以跨越else if(i == 0 && tree[lid].sum == 0)//左區間全空tree[id].lmax[i] += tree[rid].lmax[i];tree[id].rmax[i] = tree[rid].rmax[i];if(i == 1 && tree[rid].sum == tree[rid].r - tree[rid].l + 1)tree[id].rmax[i] += tree[lid].rmax[i];else if(i == 0 && tree[rid].sum == 0)tree[id].rmax[i] += tree[lid].rmax[i];tree[id].max[i] = tree[lid].rmax[i] + tree[rid].lmax[i];//中間tree[id].max[i] = max(tree[id].max[i], tree[lid].max[i]);//繼承子區間tree[id].max[i] = max(tree[id].max[i], tree[rid].max[i]);}} void build(int id, int l, int r){tree[id].l = l, tree[id].r = r, tree[id].lazy = -1;if(l == r){tree[id].sum = v[l];tree[id].max[0] = tree[id].lmax[0] = tree[id].rmax[0] = v[l] == 0;tree[id].max[1] = tree[id].lmax[1] = tree[id].rmax[1] = v[l] == 1;return ;}int mid = (l + r) >> 1;build(lid, l, mid), build(rid, mid + 1, r);pushup(id);} void pushdown(int id){if(tree[id].lazy != -1){//優先級最高tree[id].rev = 0;//清空標記int val = tree[id].lazy;tree[lid].sum = (tree[lid].r - tree[lid].l + 1) * val;tree[rid].sum = (tree[rid].r - tree[rid].l + 1) * val;tree[lid].lazy = tree[rid].lazy = val;tree[lid].rev = tree[rid].rev = 0;tree[lid].max[val] = tree[lid].lmax[val] = tree[lid].rmax[val] = tree[lid].r - tree[lid].l + 1;tree[lid].max[val ^ 1] = tree[lid].lmax[val ^ 1] = tree[lid].rmax[val ^ 1] = 0;tree[rid].max[val] = tree[rid].lmax[val] = tree[rid].rmax[val] = tree[rid].r - tree[rid].l + 1;tree[rid].max[val ^ 1] = tree[rid].lmax[val ^ 1] = tree[rid].rmax[val ^ 1] = 0;tree[id].lazy = -1;}if(tree[id].rev){tree[lid].sum = (tree[lid].r - tree[lid].l + 1) - tree[lid].sum;tree[rid].sum = (tree[rid].r - tree[rid].l + 1) - tree[rid].sum;if(tree[lid].lazy != -1)tree[lid].lazy ^= 1;//綜合考慮優先級, 對其他標記的影響else tree[lid].rev ^= 1;if(tree[rid].lazy != -1)tree[rid].lazy ^= 1;else tree[rid].rev ^= 1;swap(tree[lid].max[0], tree[lid].max[1]);swap(tree[lid].lmax[0], tree[lid].lmax[1]);swap(tree[lid].rmax[0], tree[lid].rmax[1]);swap(tree[rid].max[0], tree[rid].max[1]);swap(tree[rid].lmax[0], tree[rid].lmax[1]);swap(tree[rid].rmax[0], tree[rid].rmax[1]);tree[id].rev = 0;}} void update(int id, int val, int l, int r){pushdown(id);if(tree[id].l == l && tree[id].r == r){if(val == 0 || val == 1){tree[id].sum = (tree[id].r - tree[id].l + 1) * val;tree[id].lazy = val;tree[id].max[val] = tree[id].lmax[val] = tree[id].rmax[val] = tree[id].r - tree[id].l + 1;tree[id].max[val ^ 1] = tree[id].lmax[val ^ 1] = tree[id].rmax[val ^ 1] = 0;}else if(val == 2){tree[id].sum = (tree[id].r - tree[id].l + 1) - tree[id].sum;tree[id].rev ^= 1;swap(tree[id].max[0], tree[id].max[1]);swap(tree[id].lmax[0], tree[id].lmax[1]);swap(tree[id].rmax[0], tree[id].rmax[1]);}return ;}int mid = (tree[id].l + tree[id].r) >> 1;if(mid < l)update(rid, val, l, r);else if(mid >= r)update(lid, val, l, r);else update(lid, val, l, mid), update(rid, val, mid + 1, r);pushup(id);} int query(int id, int l, int r){pushdown(id);if(tree[id].l == l && tree[id].r == r)return tree[id].sum;int mid = (tree[id].l + tree[id].r) >> 1;if(mid < l)return query(rid, l, r);else if(mid >= r)return query(lid, l, r);else return query(lid, l, mid) + query(rid, mid + 1, r);} seg_tree Q_max(int id, int l, int r){pushdown(id);if(tree[id].l == l && tree[id].r == r)return tree[id];int mid = (tree[id].l + tree[id].r) >> 1;if(mid < l)return Q_max(rid, l, r);else if(mid >= r)return Q_max(lid, l, r);else{seg_tree ret, L = Q_max(lid, l, mid), R = Q_max(rid, mid + 1, r);ret.sum = L.sum + R.sum;REP(i, 0, 1){ret.lmax[i] = L.lmax[i];if(i == 1 && L.sum == L.r - L.l + 1)//左區間全滿ret.lmax[i] += R.lmax[i];//可以跨越else if(i == 0 && L.sum == 0)//左區間全空ret.lmax[i] += R.lmax[i];ret.rmax[i] = R.rmax[i];if(i == 1 && R.sum == R.r - R.l + 1)ret.rmax[i] += L.rmax[i];else if(i == 0 && R.sum == 0)ret.rmax[i] += L.rmax[i];ret.max[i] = L.rmax[i] + R.lmax[i];//中間ret.max[i] = max(ret.max[i], L.max[i]);//繼承子區間ret.max[i] = max(ret.max[i], R.max[i]);}return ret;}} int main(){num = RD(), na = RD();REP(i, 1, num)v[i] = RD();build(1, 1, num);while(na--){int cmd = RD(), l = RD(), r = RD();l++, r++;if(cmd == 0)update(1, 0, l, r);else if(cmd == 1)update(1, 1, l, r);else if(cmd == 2)update(1, 2, l, r);else if(cmd == 3)printf("%d\n", query(1, l, r));else printf("%d\n", Q_max(1, l, r).max[1]);}return 0;}

    轉載于:https://www.cnblogs.com/Tony-Double-Sky/p/9823463.html

    總結

    以上是生活随笔為你收集整理的P2572 [SCOI2010]序列操作的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。