无聊的数列

题目

sol:
线段树维护等差数列。lazy_tag维护首项和公差。pushdown时将首项和公差累加到子节点上去。应重新计算右节点的首项。

#include <iostream>

#include <cstring>

#include <cstdio>



using namespace std;



const int N = 1e5 + 100;



struct Tree {

	int l, r;

	int v, fir, d;

} tr[N << 2];



int n, m;

int a[N];





void build(int u, int l, int r) {

	tr[u].l = l, tr[u].r = r;

	if( l == r)	{

		tr[u].v = a[l]; 

		return;

	}

	int mid = tr[u].l + tr[u].r >> 1;

	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);

}



void pushdown(int u) {

	if( tr[u].fir || tr[u].d) {

		Tree & ls = tr[u << 1], &rs = tr[u << 1 | 1];

		ls.fir += tr[u].fir;

		ls.d += tr[u].d;

		ls.v += tr[u].fir;

		int first = tr[u].fir + (ls.r - ls.l + 1) * tr[u].d;//右侧的首项 

		rs.fir += first;

		rs.d += tr[u].d;

		rs.v += first;

		tr[u].d = 0;

		tr[u].fir = 0;

	}

}



void change(int u, int l, int r, int k, int d) {

	if( tr[u].l >= l && tr[u].r <= r) {

		int first = k + (tr[u].l - l) * d;

		tr[u].fir += first;

		tr[u].d += d;

		tr[u].v += first;

		return;

	}

	pushdown(u);

	int mid = tr[u].l + tr[u].r >> 1;

	if( l <= mid)	change(u << 1, l, r, k, d);

	if( r > mid)	change(u << 1 | 1, l, r, k, d);

}



int query(int u, int k) {

	if( tr[u].l == tr[u].r)	{

		return tr[u].v;

	}

	pushdown(u);

	int mid = tr[u].l + tr[u].r >> 1;

	if( k <= mid)	

	    return query(u << 1, k);

	else 

	    return query(u << 1 | 1, k);

}



int main()

{

//	freopen("E:\\data.in.txt", "r", stdin);

//	freopen("E:\\data.out.txt", "w", stdout);

	scanf("%d%d", &n, &m);

	for(int i = 1; i <= n; i ++) {

		scanf("%d", &a[i]); 

	}

	build(1, 1, n);

	while(m --) {

		int opt, l, r, k, d;

		scanf("%d", &opt);

		if( opt == 1) {

			scanf("%d%d%d%d", &l, &r, &k, &d);

			change(1, l, r, k, d);

		}

		else {

			scanf("%d", &k);

			printf("%d\n", query(1, k));

		}

	}

	return 0;

} 
posted @ 2020-10-04 21:51  王雨阳  阅读(78)  评论(0编辑  收藏  举报