树状数组区间加区间求和 and 历史版本和
spider_oyster · · 个人记录
其实很简单。
考虑只有区间加,即树状数组维护一个差分数组。
设
假设现在询问
可以发现第
转化为求:
直接维护即可。
struct BIT{
int c1[N],c2[N];
void upd(int x,int v) {for(int V=x*v;x<=n;x+=x&-x) c1[x]+=v,c2[x]+=V;}
int sum(int x) {int s1=0,s2=0;for(int y=x;y;y^=y&-y) s1+=c1[y],s2+=c2[y];return (x+1)*s1-s2;}
int qsum(int l,int r) {return sum(r)-sum(l-1);}
}tr;
下面说历史版本和。
引入时间的概念,记当前时间为
考虑一个位置
分别维护
struct BIT{
int c1[N],c2[N];
void upd(int x,int v) {for(int V=x*v;x<=n;x+=x&-x) c1[x]+=v,c2[x]+=V;}
int sum(int x) {int s1=0,s2=0;for(int y=x;y;y^=y&-y) s1+=c1[y],s2+=c2[y];return (x+1)*s1-s2;}
int qsum(int l,int r) {return sum(r)-sum(l-1);}
}tr1,tr2;
void upd(int l,int r,int v,int t) //区间 [l,r] + v,当前时间为 t
{
tr1.upd(l,v),tr1.upd(r+1,-v);
tr2.upd(l,v*t),tr2.upd(r+1,-v*t);
}
int qsum(int l,int r,int t) {return tr1.qsum(l,r)*(t+1)-tr2.qsum(l,r);}
一些邪道:
区间覆盖 + 历史版本和:用 ODT + 树状数组。
区间取 max/min + 历史版本和:吉司机线段树,当线段树结点 mn[k]=mx[k](区间值相同)的时候再用树状数组维护。复杂度显然是错的,但是没有人会想到这种做法 -> 没有人卡 -> 正确的。模拟赛用了好几次了,亲测有效。