HDU-1698(線段樹set把區間全部更改,懶人標記)
阿新 • • 發佈:2018-12-14
#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;
}