标签:algo mat 算法 std char 信息 cto using png
①对于要求的输出,需要维护哪些信息(线段树节点里要存什么)?
②这些信息是否可以直接得到?
③如果不能,需要维护哪些信息来间接获得?
两件事:由上而下干什么? 由下而上干什么?
由上而下的过程——初始化
由下而上的过程——合并区间信息
从上往下跑一圈又必须要倒回去的算法——递归。
那么就是递归实现的喽。
理论上是2n-1的空间,但是你递归建立的时候当前节点为r
,那么左右孩子分别是2r,2r+1,此时编译器并不知道递归已结束,
因为你的结束条件是在递归之前的,所以编译器会认为下标访问出错,也就是空间开小了,
应该再开大2倍。有时候可能你发现开2,3倍的空间也可以AC,那只是因为测试数据并没有那么大。
主要的思路就是递归加二分
看看代码吧(~~怀念那学长看着我打代码,强行改我码风的日子)
void build(ll l,ll r,ll rt) {
t[rt].len = r - l + 1;
if(l == r) {
t[rt].sum = read();
return;
}
ll m = (l + r) >> 1;
build(l, m, lson);
build(m + 1, r ,rson);
pushup(rt);
}
知道二分与递归之后,单点查询那不就成了一个,二分求解的过程了嘛
```cpp
void ask(int k)
{
if(tree[k].l==tree[k].r) //当前结点的左右端点相等,那么说明是叶子节点,是最终答案
{
ans=tree[k].w;
return ;
}
int m=(tree[k].l+tree[k].r)/2; // 二分查找
if(x<=m) ask(k2);
else ask(k2+1);
}
与单点查询没有什么区别,就是加了修改操作
还有一个回溯的过程
void add(int k)
{
if(tree[k].l==tree[k].r)//找到目标位置
{
tree[k].w+=y;
return;
}
int m=(tree[k].l+tree[k].r)/2;
if(x<=m) add(k*2);
else add(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;//所有包含结点k的结点状态更新
}
因为线段树的时候,有一些节点虽然我们下放了值了,也加上了,但是我们并没有用到这个地方
那么我们可以现在查询到的地方打上一个lazy标记(称为懒标记),然后每次查到这里的时候
就将当前的区间维护的值,与lazy标记处理一下就好了,这样我们就没有必要再向下跑到叶子节点
然后在合并区间信息了,很麻烦,也很慢...
当他区间修改的时候,无非就是三种情况
like this
like this
like this
看一下代码吧
void updata(ll L,ll R,ll c,ll l,ll r,ll rt){
if(L <= l && r <= R){
t[rt].sum += t[rt].len * c;
t[rt].lazy += c;
return ;
}
pushdown(rt);
ll m = (l + r) >> 1;
if(L <= m) updata(L,R,c,l,m,lson);
if(R > m) updata(L,R,c,m + 1,r,rson);
pushup(rt);
}
ll query(ll L,ll R,ll l,ll r,ll rt){
if(L <= l && r <= R) return t[rt].sum;
pushdown(rt);
ll m = (l + r) >> 1,ans=0;
if(L <= m) ans+=query(L, R, l, m, lson);
if(R > m) ans+=query(L, R, m + 1, r, rson);
return ans;
}
最后合并总的代码(因为单点查询与单点修改可以仿照区间查询与区间修改上来我就不放了)
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<string>
#define ll long long
#define N 1000010
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
ll n,m,rt;
struct node {
ll sum,lazy,len;
} t[N << 2 | 1];
ll read() {
ll s=0,f=0;
char ch=getchar();
while(!isdigit(ch)) f|=(ch=='-'),ch=getchar();
while(isdigit(ch)) s=s*10+(ch^48),ch=getchar();
return f?-s:s;
}
void build(ll l,ll r,ll rt);
void pushup(ll rt);
void pushdown(ll rt);
void updata(ll L,ll R,ll c,ll l,ll r,ll rt);
ll query(ll L,ll R,ll l,ll r,ll rt);
int main() {
n = read(), m = read();
build(1,n,1);
for(ll i = 1, opt, l, r, k; i <= m; i++){
opt = read(),l = read(),r = read();
if(opt == 1){k = read();updata(l,r,k,1,n,1);}
else printf("%lld\n",query(l,r,1,n,1));
}
return 0;
}
void build(ll l,ll r,ll rt) {
t[rt].len = r - l + 1;
if(l == r) {
t[rt].sum = read();
return;
}
ll m = (l + r) >> 1;
build(l, m, lson);
build(m + 1, r ,rson);
pushup(rt);
}
void pushup(ll rt) {
t[rt].sum = t[lson].sum + t[rson].sum;
}
void pushdown(ll rt) {
if(t[rt].lazy) {
t[lson].lazy += t[rt].lazy;
t[rson].lazy += t[rt].lazy;
t[lson].sum += t[lson].len * t[rt].lazy;
t[rson].sum += t[rson].len * t[rt].lazy;
t[rt].lazy = 0;
}
}
void updata(ll L,ll R,ll c,ll l,ll r,ll rt){
if(L <= l && r <= R){
t[rt].sum += t[rt].len * c;
t[rt].lazy += c;
return ;
}
pushdown(rt);
ll m = (l + r) >> 1;
if(L <= m) updata(L,R,c,l,m,lson);
if(R > m) updata(L,R,c,m + 1,r,rson);
pushup(rt);
}
ll query(ll L,ll R,ll l,ll r,ll rt){
if(L <= l && r <= R) return t[rt].sum;
pushdown(rt);
ll m = (l + r) >> 1,ans=0;
if(L <= m) ans+=query(L, R, l, m, lson);
if(R > m) ans+=query(L, R, m + 1, r, rson);
return ans;
}
标签:algo mat 算法 std char 信息 cto using png
原文地址:https://www.cnblogs.com/zzz-hhh/p/11216488.html