(」・ω・)」うー!(/・ω・)/にゃー!
——潜行吧奈亚子

线段树

线段树

概念

其实就是一个二叉树,运用了分治的思想。将一个有序数组从中间截断,并不断的截,直到最后每组只剩单一元素时即可,由于可以方便的进行区间修改区间求和,于是叫做线段树

建树

思路: 先确定边界条件,即\(L=R\)时,在线段树上添加结点,否则就把区间截成两段,再次进行操作。代码如下:

void build(int l, int r, int t)//建树 
{
    if (l == r)
    {
        w[l] = s[t]; //赋值
	return ;
    }
    int mid = (l + r) / 2;//在中间找中点
   //注意记号加一(t)
    build(l, mid, ++t);//左边建树(l~mid)
    build(mid + 1, r, ++t);//右边建树(mid+1~r)
    s[t] = s[2 * t] + s[2 * t + 1];//线段树性质,
}

更改

void update(int l, int r, int c, int s, int t, int p)//更新 
{
    if (l <= s && t <= r) 
    {
        b[p] += (t - s + 1) * c;
	lazy_tag[p] += c;
    	return;
    }  
    int m = (s + t) / 2;
    if (lazy_tag[p] && s != t) 
    {
	b[p * 2] += lazy_tag[p] * (m - s + 1); 
	b[p * 2 + 1] += lazy_tag[p] * (t - m);
   	lazy_tag[p * 2] += lazy_tag[p];
	lazy_tag[p * 2 + 1] += lazy_tag[p];  
    	lazy_tag[p] = 0;                            
    }
    if (l <= m) 
    {
	update(l, r, c, s, m, p * 2);
    }
    if (r > m) 
    {
        update(l, r, c, m + 1, t, p * 2 + 1);
    }
    b[p] = b[p * 2] + b[p * 2 + 1];
}

求和

思路: 就是在一个区间中查找另一区间,不断缩短搜索范围,直到完全匹配就返回答案,否则在左右两边判断是否含有当前部分。代码如下:

void getsum(int L, int R, int l, int r, int t)//求和 
{
    if (L <= l && R <= r)
    {
	return s[t];//找到区间了,就返回
    }
    int mid = l + (r - l) / 2;//找到中点
    int sum = 0;//定义和,初始为0
    if (l <= mid)//如果在左区间有部分
    {
	sum += getsum(L, R, l, mid, p * 2);//把区间截断,只留左边继续递归,并把和累加
    }
    if (r > mid)//如果再右区间有部分
    {
  	sum += getsum(L, R, mid + 1, r, p * 2 + 1);//把区间截断,只留右边继续递归,并把和累加
    }
}
posted @ 2021-12-25 22:12  GalaxyOier  阅读(13)  评论(0)    收藏  举报