1. 程式人生 > >HDU-1698(線段樹set把區間全部更改,懶人標記)

HDU-1698(線段樹set把區間全部更改,懶人標記)

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 5;
long long dat[maxn << 2], setv[maxn << 2];
int v, ql, qr;//該模板從dat[1]開始,父節點儲存子節點之和,v存入變化量
void init(int n) {
	fill(dat+1, dat+(n<<2), 1);
	fill(setv+1, setv+(n<<2), -1);//set與add的區別是add是疊加關係,而set是覆蓋關係,後一次set會覆蓋前一次set,所以set標記必須下推
} void pushdown(int o) { if (setv[o] != -1) { setv[o << 1] = setv[o << 1 | 1] = setv[o]; setv[o] = -1; } } void maintain(int o, int L, int R) { if (setv[o]!=-1) dat[o] = setv[o]*(R-L+1); else if(L<R)dat[o]=dat[o<<1]+dat[
o<<1|1];//父節點的值加上區間長度乘set,就是父節點現在的值 }//L=R的時候說明可能沒有子節點了,不用更新 void update(int o, int L, int R) { if (ql <= L && R <= qr) setv[o] = v; else { pushdown(o);//往下推一層,直到完全包含 int M = (L + R) >> 1; if (ql <= M) update(o << 1, L, M); //左子節點等於父節點乘二 else maintain(o << 1
, L, M); if(M<qr) update(o << 1 | 1, M + 1, R);//右子節點還要加一 else maintain(o << 1 | 1, M + 1, R); } maintain(o, L, R); } long long query(int o, int L, int R) {//add是路途上經過的所有add標記之和 if (ql <= L && R <= qr) { return dat[o];//完全包含 } if (qr < L || R < ql) return 0;//部分包含 if (setv[o] != -1) return (long long)setv[o] * (min(R, qr) - max(L, ql) + 1);//遇到set說明這個標記下面的都要被改變,但是不一定都被包含在qr,ql中所以才有了max,min long long s = 0;//部分包含且有set int M = (L + R) >> 1; if (ql <= M)s += query(o << 1, L, M);//繼續遞迴,最後一定會分成上面三種區間並得到結果 if (M < qr) s += query(o << 1 | 1, M + 1, R); return s; } int main() { int T;scanf("%d", &T); for(int kase=1;kase<=T;kase++){ int n, q; scanf("%d%d", &n, &q); init(n); while (q--) { scanf("%d%d%d", &ql, &qr, &v); update(1, 1, n); } ql = 1;qr = n; printf("Case %d: The total value of the hook is %lld.\n", kase, query(1, 1, n)); } return 0; }