1. 程式人生 > >牛客練習賽 資料結構 線段樹

牛客練習賽 資料結構 線段樹

連結:https://www.nowcoder.com/acm/contest/200/B
來源:牛客網
 

qn姐姐最好了~

    qn姐姐給你了一個長度為n的序列還有m次操作讓你玩,

    1 l r 詢問區間[l,r]內的元素和

    2 l r 詢問區間[l,r]內的元素的平方 

    3 l r x 將區間[l,r]內的每一個元素都乘上x

    4 l r x 將區間[l,r]內的每一個元素都加上x

 

輸入描述:

第一行兩個數n,m

接下來一行n個數表示初始序列

就下來m行每行第一個數為操作方法opt,

若opt=1或者opt=2,則之後跟著兩個數為l,r

若opt=3或者opt=4,則之後跟著三個數為l,r,x

操作意思為題目描述裡說的

輸出描述:

對於每一個操作1,2,輸出一行表示答案

 

示例1

輸入

複製

5 6
1 2 3 4 5
1 1 5
2 1 5
3 1 2 1
4 1 3 2
1 1 4
2 2 3

輸出

複製

15
55
16
41

線段樹懶惰標記:

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define ll long long
const int maxm = 10005;
int a[maxm];
struct node
{
	ll val, sb, sc, l, r, s2;
	ll add, mdd;
}tr[maxm * 20];
void down(int num)
{
	int l = tr[num].l, r = tr[num].r;
	ll add = tr[num].add, mdd = tr[num].mdd;
	if (add)
	{
		tr[num].s2 += 2 * tr[num].val*add + (r - l + 1)*add*add;
		tr[num].val += add*(r - l + 1);
		if (tr[num].l != tr[num].r)
		{
			down(num * 2), down(num * 2 + 1);
			tr[num * 2].add = tr[num * 2 + 1].add = add;
		}
		tr[num].add = 0;
	}
	if (mdd > 1)
	{
		tr[num].val *= mdd;
		tr[num].s2 *= (mdd*mdd);
		if (tr[num].l != tr[num].r)
		{
			down(num * 2), down(num * 2 + 1);
			tr[num * 2].mdd = tr[num * 2 + 1].mdd = tr[num].mdd;
		}
		tr[num].mdd = 1;
	}
}
void build(int l, int r, int num)
{
	tr[num].l = l, tr[num].r = r;
	tr[num].add = 0, tr[num].mdd = 1;
	if (l == r)
	{
		tr[num].val = a[l];
		tr[num].s2 = a[l] * a[l];
		tr[num].sb = tr[num].sc = 0;
		tr[num].add = 0, tr[num].mdd = 1;
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, num * 2);
	build(mid + 1, r, num * 2 + 1);
	tr[num].val = tr[num * 2].val + tr[num * 2 + 1].val;
	tr[num].s2 = tr[num * 2].s2 + tr[num * 2 + 1].s2;
}
void update(int l, int r, ll val, int num, int flag)
{
	if (tr[num].add || tr[num].mdd > 1) down(num);
	if (l == tr[num].l&&r == tr[num].r)
	{
		if (flag == 1) tr[num].add += val;
		else tr[num].mdd *= val;
		down(num);
		return;
	}
	int mid = (tr[num].l + tr[num].r) / 2;
	if (mid >= r) update(l, r, val, num * 2, flag);
	else if (mid < l) update(l, r, val, num * 2 + 1, flag);
	else
	{
		update(l, mid, val, num * 2, flag);
		update(mid + 1, r, val, num * 2 + 1, flag);
	}
	down(num * 2), down(num * 2 + 1);
	tr[num].val = tr[num * 2].val + tr[num * 2 + 1].val;
	tr[num].s2 = tr[num * 2].s2 + tr[num * 2 + 1].s2;
}
ll query(int l, int r, int num, int flag)
{
	if (tr[num].add || tr[num].mdd > 1) down(num);
	if (tr[num].l >= l&&tr[num].r <= r)
	{
		if (flag == 1) return tr[num].val;
		else return tr[num].s2;
	}
	int mid = (tr[num].l + tr[num].r) / 2;
	ll ans = 0;
	if (mid >= r)
		ans += query(l, r, num * 2, flag);
	else if (mid < l)
		ans += query(l, r, num * 2 + 1, flag);
	else
	{
		ans += query(l, mid, num * 2, flag);
		ans += query(mid + 1, r, num * 2 + 1, flag);
	}
	return ans;
}
int main()
{
	int n, i, j, k, sum, m, flag, l, r, x;
	scanf("%d%d", &n, &m);
	for (i = 1;i <= n;i++)
		scanf("%d", &a[i]);
	build(1, n, 1);
	while (m--)
	{
		scanf("%d%d%d", &flag, &l, &r);
		if (flag == 1 || flag == 2)
			printf("%lld\n", query(l, r, 1, flag));
		else
		{
			scanf("%d", &x);
			if (flag == 3) update(l, r, x, 1, 2);
			else update(l, r, x, 1, 1);
		}
	}
	return 0;
}