線段樹~
這(d)道(q)題(s)告訴我說:「你沒學過線段樹」
嗯……
這題要好好想想……qaq
來吧首先要明確的事情是
delta[now]記錄的是已經對當前點做過的,但是還沒有對當前點的兒子做過的操作嗯……
我們就這樣
慢慢的退一下
嗯 標記是給兒子用的
嗯 是給兒子用的
奉獻精神
然後,對於這個題,我們可以把所有操作統一為對該節點*x
+y
的形式
void change(int l,int r,ll add,ll mult,int p)
那麼區間乘就成了change(l,r,0,v,1);
那麼區間加就成了change(l,r,v,1,1);
標記是什麼?
對目前的答案進行標記該有的操作之後會得到真實的答案真理往往隱蔽在眾多表象的茫茫迷霧之中,而標記就像穿透這迷霧的明燈,引導著探索者到達真理的彼岸
(old_ans * mult) + add = new_old
標記的作用是引導兒子走上正軌
所以說下放標記的時候要將兒子的ans計算出來
嗯然後怎麼更新標記
這成了大問題 設
為了使得
(sum * a + b) * c + d == sum * x + y
sum * a * c + b * c + d == sum * x + y
x = a * c
y = b * c + d
然後就可以更新了~
嗯 kill
#include
#include
#include
#include
#define l(x) (x << 1)
#define r(x) (x << 1 | 1)
#define sz(x) (tree[x].r - tree[x].l + 1)
using
namespace
std;
const
int maxn = 100000 + 5;
typedef
long
long ll;
int p;
struct dot
tree[maxn << 2];
int num[maxn];
void update(int p)
void build(int l,int r,int p)
int mid = (l + r) >> 1;
build(l,mid,l(p));
build(mid + 1,r,r(p));
update(p);
return;
}void spread(int p)
void change(int l,int r,ll add,ll mult,int p)
spread(p);
int mid = (tree[p].l + tree[p].r) >> 1;
if(l <= mid)change(l,r,add,mult,l(p));
if(mid < r)change(l,r,add,mult,r(p));
update(p);
return;
}ll ask(int l,int r,int p)
int n,m;
int q,a,b;
ll v;
int main()
}return
0;}
BZOJ 1798, 維護序列
傳送門 維護乙個數列,要求支援區間加 區間乘以及查詢操作。很裸的線段樹,難點在於加法和乘法的操作順序。標記下傳時應先打乘法標記,再打加法標記,同時更新時還要用乘法標記維護加法標記。include typedef long long ll const int n 100005 int n,p,m,x,...
bzoj1798 ahoi2009 維護序列
time limit 30 sec memory limit 64 mb submit 3714 solved 1364 submit status discuss 老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。有長為n的數列,不妨設為a1,a2,an 有如下三種操作形式 1 把數列...
BZOJ 1500 維護序列
bzoj 1500 傳送門 可能平衡樹維護序列的所有操作都在這了吧 對序列的維護 fhq treap 和 splay 都能做 有幾個注意點 1 維護序列時始終記得第 k 大指的是序號,與權值無關 2 注意對0的初始化,畢竟如果無葉子結點時會用到 3 如果資料總量過大要資料 用佇列記錄被刪除的節點,同...