線段覆蓋 (線段樹)
阿新 • • 發佈:2019-03-13
chm uil 需要 eric 數組大小 clas freopen 數組 情況
有一根長度為 \(L\) 的白色條狀物。有兩種操作:
- 用一條長度為 \(T\) 的黑布蓋住條狀物的 \([a,a+T]\) 的這個區間
- 把某條黑布拿走
輸入 \(L\) 和 \(n\) 次操作,要你輸出每次操作之後
- 條狀物上有多少個黑區間
- 條狀物上黑區間的總長度
觀察出題目的詢問每次都是一樣的,其實也只有一種修改(添和刪相當於互逆操作)
我們可以建一棵線段樹
\(v\) 表示有多少個黑區間
\(len\) 表示黑區間的總長度
\(tag\) 表示該區間添加的整布條數
顯然答案就是線段樹的根節點的數據
那麽怎麽維護這些信息?
我們繼續記錄一下信息:
\(lbd\) 表示該區間左端點是否覆蓋
\(rbd\) 表示該區間右端點是否覆蓋
先看如何上傳
- 如果 懶標記為正,那麽整個區間顯然全部被覆蓋,那麽 \(v=lbd-rbd=1\),\(len=r-l+1\)
- 否則,那麽我們要通過左右兒子的信息去得到它的信息
顯然 \(lbd(x)=lbd(ls(x)),rbd(x)=rbd(rs(x)),len=len(ls(x))+len(rs(x))\),那麽 \(v\) 怎麽搞? 是 \(v(ls(x))+v(rs(x))\) 麽
值得註意的是,需要特判左右拼接的情況,即 \(rbd(ls(x))\) 和 \(lbd(rs(x))\) 都為正的時候,\(v\) 要減一
然後重點是下傳
- 首先懶標記 \(tag~+~x\)
- 如果是葉子結點,那麽我們可以直接搞,對於 \(tag\) 分類搞即可
- 否則我們繼續暴力 \(pushup\) 就行了
#include <map> #include <set> #include <ctime> #include <queue> #include <stack> #include <cmath> #include <vector> #include <bitset> #include <cstdio> #include <cctype> #include <string> #include <numeric> #include <cstring> #include <cassert> #include <climits> #include <cstdlib> #include <iostream> #include <algorithm> #include <functional> using namespace std ; //#define int long long #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define per(i, a, b) for (int i = (a); i >= (b); i--) #define loop(s, v, it) for (s::iterator it = v.begin(); it != v.end(); it++) #define cont(i, x) for (int i = head[x]; i; i = e[i].nxt) #define clr(a) memset(a, 0, sizeof(a)) #define ass(a, sum) memset(a, sum, sizeof(a)) #define lowbit(x) (x & -x) #define all(x) x.begin(), x.end() #define ub upper_bound #define lb lower_bound #define pq priority_queue #define mp make_pair #define pb push_back #define fi first #define se second #define iv inline void #define enter cout << endl #define siz(x) ((int)x.size()) #define file(x) freopen(#x".in", "r", stdin),freopen(#x".out", "w", stdout) typedef long long ll ; typedef unsigned long long ull ; typedef pair <int, int> pii ; typedef vector <int> vi ; typedef vector <pii> vii ; typedef queue <int> qi ; typedef queue <pii> qii ; typedef set <int> si ; typedef map <int, int> mii ; typedef map <string, int> msi ; const int N = 200010 ; const int INF = 0x3f3f3f3f ; const int iinf = 1 << 30 ; const ll linf = 2e18 ; const int MOD = 1000000007 ; const double eps = 1e-7 ; void print(int x) { cout << x << endl ; exit(0) ; } void PRINT(string x) { cout << x << endl ; exit(0) ; } void douout(double x){ printf("%lf\n", x + 0.0000000001) ; } template <class T> void chmin(T &a, T b) { if (a > b) a = b ; } template <class T> void chmax(T &a, T b) { if (a < b) a = b ; } int n, m ; char s[10] ; struct SegTree { int l, r, v, len, lbd, rbd, tag, sz ; #define ls(x) x << 1 #define rs(x) x << 1 | 1 #define l(x) tr[x].l #define r(x) tr[x].r #define v(x) tr[x].v #define sz(x) tr[x].sz #define len(x) tr[x].len #define lbd(x) tr[x].lbd #define rbd(x) tr[x].rbd #define tag(x) tr[x].tag } tr[N << 2] ; void pushup(int x) { if (tag(x) > 0) { lbd(x) = rbd(x) = v(x) = 1 ; len(x) = sz(x) ; } else { lbd(x) = lbd(ls(x)) ; rbd(x) = rbd(rs(x)) ; len(x) = len(ls(x)) + len(rs(x)) ; v(x) = v(ls(x)) + v(rs(x)) ; if (rbd(ls(x)) && lbd(rs(x))) v(x)-- ; } } void build(int x, int l, int r) { l(x) = l, r(x) = r, sz(x) = r(x) - l(x) + 1 ; if (l == r) return ; int mid = (l(x) + r(x)) >> 1 ; build(ls(x), l, mid) ; build(rs(x), mid + 1, r) ; // pushup(x) ; } void modify(int x, int l, int r, int v) { // cout << x << endl ; if (l <= l(x) && r(x) <= r) { tag(x) += v ; if (l(x) == r(x)) { // 葉子結點 if (tag(x) > 0) { len(x) = lbd(x) = rbd(x) = v(x) = 1 ; } else { len(x) = lbd(x) = rbd(x) = v(x) = 0 ; } } else { pushup(x) ; } return ; } int mid = (l(x) + r(x)) >> 1 ; if (l <= mid) modify(ls(x), l, r, v) ; if (mid < r) modify(rs(x), l, r, v) ; pushup(x) ; } signed main(){ // freopen("test.in", "r", stdin) ; // freopen("test.out", "w", stdout) ; scanf("%d%d", &n, &m) ; build(1, 0, n) ; rep(i, 1, m) { int op, x, v ; scanf("%d%d%d", &op, &x, &v) ; if (op == 1) modify(1, x, x + v - 1, 1) ; else modify(1, x, x + v - 1, -1) ; printf("%d %d\n", v(1), len(1)) ; } return 0 ; } /* 寫代碼時請註意: 1.ll?數組大小,邊界?數據範圍? 2.精度? 3.特判? 4.至少做一些 思考提醒: 1.最大值最小->二分? 2.可以貪心麽?不行dp可以麽 3.可以優化麽 4.維護區間用什麽數據結構? 5.統計方案是用dp?模了麽? 6.逆向思維? */
線段覆蓋 (線段樹)