大佬详解:look here
前情提要qaq:
结构体里面存下l——左边界,r——右边界,w——数值,f——懒标记
建树:
void build(int k,int ll,int rr){
tree[k].l = ll;
tree[k].r = rr;
if(tree[k].l == tree[k].r){//到最下面子节点读入
scanf("%d",&tree[k].w);
return ;
}
int m = (ll + rr) / 2;
build(k * 2,ll,m);//左儿子
build(k * 2 + 1,m + 1,rr);//右儿子
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;//更新父节点
}
down函数——将懒标记向下传递
void down(int k){
tree[k * 2].f += tree[k].f;
tree[k * 2 + 1].f += tree[k].f;//继承标记
tree[k * 2].w += tree[k].f * (tree[k * 2].r - tree[k * 2].l + 1);
tree[k * 2 + 1].w += tree[k].f * (tree[k * 2 + 1].r - tree[k * 2 + 1].l + 1);//更新子树w
tree[k].f = 0;//好的它解脱了
}
down的引入主要是因为 区间修改的时候只修改对区间有用的点所以引入懒标记f 简言之就是如果(5,8)都在修改范围就再这个节点继承标记不再向下传递 也是因为这个原因 引入f后我们的单点查询修改以及区间查询收到影响 需要加一条 if(tree[k].f) down(k);
这是因为修改时(5,8)这个节点已经代表它所辖的子节点全部(+x)[这里为了好说假设我们是对区间加上一个数哈
而我再对这下面的子节点查询修改时想要获得区间修改后的更修 就必须把(5,8)的懒标记向下传递。
emmm应该是说清楚了叭
单点查询:
void ask_p(int k){
if(tree[k].l == tree[r]){
ans = tree[k].w;
return ;
}
if(tree[k].f) down(k);
int m = (tree[k].l + tree[k].r) / 2;
if(x <= m) ask_p(k * 2);//x是要ask的点
else ask_p(k * 2 + 1);
}
单点修改:
void chan_p(int k){
if(tree[k].l == tree[k].r){
tree[k].w += y;
return ;
}
if(tree[k].f) down(k);
int m = (tree[k].l + tree[k].r) / 2;
if(x <= m) chan_p(k * 2);
else chan_p(k * 2 + 1);
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
}
区间查询:
void ask_val(int k){//查询 a b
if(tree[k].l >= a && tree[k].r <= b){
ans += tree[k].w;//这里以求和为例
return ;
}
if(tree[k].f) down(k);
int m = (tree[k].l + tree[k].r) / 2;
if(a <= m) ask_val(k * 2);
if(b > m) ask_val(k * 2 + 1);
}
区间修改:
void chan_val(int k){
if(tree[k].l >= a && tree[k].r <= b){//all in
tree[k].w += (tree[k].r - tree[k].l + 1) * y;
tree[k].f += y;
return ;
}
if(tree[k].f) down(k);
int m = (tree[k].l + tree[k].r) / 2;
if(a <= m) chan_val(k * 2);
if(b > m) chan_val(k * 2 + 1);
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
}
还是敌兵布阵^_^
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
const int maxn = (5e4 + 5) * 4;
int t,n,pos,ad,ans;
string cur;
struct NODE{
int l,r,f,w;
}tree[maxn];
void build(int k,int ll,int rr){
tree[k].l = ll;
tree[k].r = rr;
if(tree[k].l == tree[k].r){
scanf("%d",&tree[k].w);
return ;
}
int m = (ll + rr) / 2;
build(k * 2,ll,m);
build(k * 2 + 1,m + 1,rr);
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
}
/*
void down(int k){
tree[k * 2].f += tree[k].f;
tree[k * 2 + 1].f += tree[k].f;
tree[k * 2].w += tree[k].f * (tree[k * 2].r - tree[k * 2 + 1].r + 1);
tree[k * 2 + 1].w += tree[k].f * (tree[k * 2 + 1].r - tree[k * 2 + 1].l + 1);
tree[k].f = 0;
}
*/
void chan_p(int k){
if(tree[k].l == tree[k].r){
tree[k].w += ad;
return ;
}
int m = (tree[k].l + tree[k].r) / 2;
if(pos <= m) chan_p(k * 2);
else chan_p(k * 2 + 1);
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
}
void ask_val(int k){
if(tree[k].l >= pos && tree[k].r <= ad){
ans += tree[k].w;
return ;
}
int m = (tree[k].l + tree[k].r) / 2;
if(pos <= m) ask_val(k * 2);
if(ad > m) ask_val(k * 2 + 1);
}
int main()
{
scanf("%d",&t);
for(int i = 1;i <= t; i++){
scanf("%d",&n);
build(1,1,n);
cout << "Case " << i << ":"<<endl;
while(cin >> cur){
if(cur == "End") break;
scanf("%d %d",&pos,&ad);
if(cur == "Add") chan_p(1);
else if(cur == "Sub"){
ad = ad * (-1);
chan_p(1);
}
else {
ans = 0;
ask_val(1);
cout << ans << endl;
}
}
}
}