P3373 【模板】线段树 2(线段树)、(分块)

题目描述

如题,已知一个数列,你需要进行下面三种操作:

  • 将某区间每一个数乘上 x

  • 将某区间每一个数加上 x

  • 求出某区间每一个数的和

输入格式

第一行包含三个整数 n,m,p分别表示该数列数字的个数、操作的总个数和模数。

第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。

接下来 m 行每行包含若干个整数,表示一个操作,具体如下:

操作 1: 格式:1 x y k 含义:将区间 [x,y]内每个数乘上 k

操作 2: 格式:2 x y k 含义:将区间 [x,y] 内每个数加上 k

操作 3: 格式:3 x y 含义:输出区间 [x,y] 内每个数的和对 p 取模所得的结果

输出格式

输出包含若干行整数,即为所有操作 3 的结果。

输入输出样例

输入 #1复制

5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4

输出 #1

17
2

暂且当个板子记录一下(* ̄︶ ̄) 

线段树写法:

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 1e5 + 7;
int p;
long long a[N];
struct node
{
    long long v, mul, add;
}st[N << 2];

void build(int root, int l, int r)
{
    st[root].mul = 1;
    st[root].add = 0;
    if (l == r) {
        st[root].v = a[l];
    }
    else {
        int m = (l + r) / 2;
        build(root << 1, l, m);
        build(root << 1 | 1, m + 1, r);
        st[root].v = st[root << 1].v + st[root << 1 | 1].v;
    }
    st[root].v %= p;
    return;
}

void pushdown(int root, int l, int r)
{
    int m = (l + r) / 2;
    st[root << 1].v = (st[root << 1].v * st[root].mul + st[root].add * (m - l + 1)) % p;
    st[root << 1 | 1].v = (st[root << 1 | 1].v * st[root].mul + st[root].add * (r - m)) % p;
    st[root << 1].mul = (st[root << 1].mul * st[root].mul) % p;
    st[root << 1 | 1].mul = (st[root << 1 | 1].mul * st[root].mul) % p;
    st[root << 1].add = (st[root << 1].add * st[root].mul + st[root].add) % p;
    st[root << 1 | 1].add = (st[root << 1 | 1].add * st[root].mul + st[root].add) % p;
    st[root].mul = 1;
    st[root].add = 0;
    return;
}

void mul(int root, int stdl, int stdr, int l, int r, long long k)
{
    if (r < stdl || stdr < l)
        return;
    if (l <= stdl && stdr <= r)
    {
        st[root].v = (st[root].v * k) % p;
        st[root].mul = (st[root].mul * k) % p;
        st[root].add = (st[root].add * k) % p;
        return;
    }
    pushdown(root, stdl, stdr);
    int m = (stdl + stdr) / 2;
    mul(root << 1, stdl, m, l, r, k);
    mul(root << 1 | 1, m + 1, stdr, l, r, k);
    st[root].v = (st[root << 1].v + st[root << 1 | 1].v) % p;
    return;
}

void add(int root, int stdl, int stdr, int l, int r, long long k)
{
    if (r < stdl || stdr < l)
        return;
    if (l <= stdl && stdr <= r)
    {
        st[root].add = (st[root].add + k) % p;
        st[root].v = (st[root].v + k * (stdr - stdl + 1)) % p;
        return;
    }
    pushdown(root, stdl, stdr);
    int m = (stdl + stdr) / 2;
    add(root << 1, stdl, m, l, r, k);
    add(root << 1 | 1, m + 1, stdr, l, r, k);
    st[root].v = (st[root << 1].v + st[root << 1 | 1].v) % p;
    return;
}

long long query(int root, int stdl, int stdr, int l, int r)
{
    if (r < stdl || stdr < l)
        return 0;
    if (l <= stdl && stdr <= r)
        return st[root].v;
    pushdown(root, stdl, stdr);
    int m = (stdl + stdr) / 2;
    return (query(root << 1, stdl, m, l, r) + query(root << 1 | 1, m + 1, stdr, l, r)) % p;
}

void solve()
{
    int n, m;
    scanf("%d%d%d", &n, &m, &p);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    build(1, 1, n);
    while (m--)
    {
        int chk;
        scanf("%d", &chk);
        int x, y;
        long long k;
        if (chk == 1)
        {
            scanf("%d%d%lld", &x, &y, &k);
            mul(1, 1, n, x, y, k);
        }
        else if (chk == 2)
        {
            scanf("%d%d%lld", &x, &y, &k);
            add(1, 1, n, x, y, k);
        }
        else
        {
            scanf("%d%d", &x, &y);
            printf("%lld\n", query(1, 1, n, x, y));
        }
    }
}

int main()
{
    solve();
    return 0;
}

分块写法:

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <iomanip>
#include <cmath>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define bug(x) cout<<#x<<"=="<<x<<endl;
using namespace std;
typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> PII;

const int maxn = 1e5 + 5;
ll mod;
ll n, m;
ll num;//块的数量
ll l[maxn], r[maxn];//第i个数所在的块最左,最右的点
ll len[maxn], belong[maxn];//len表示第i块的大小,belong表示第i个数所在的块是第几块
ll a[maxn], sum[maxn];//第i块的和
ll tag[maxn];//每个整块加的数
ll mul[maxn];//每个整块乘的数

inline int read() {
	int s = 0, w = 1; char ch = getchar();
	while (ch < '0' || ch>'9') { if (ch == '-') w = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * w;
}

inline void write(int x) {
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

void build() {//建块
	num = sqrt(n);
	for (int i = 1; i <= num; ++i) {
		l[i] = n / num * (i - 1) + 1;
		r[i] = n / num * i;
	}
	r[num] = n;
	for (int i = 1; i <= num; ++i) {
		for (int j = l[i]; j <= r[i]; ++j) {
			belong[j] = i;
		}
	}
	for (int i = 1; i <= num; ++i) {
		len[i] = r[i] - l[i] + 1;
	}
	for (int i = 1; i <= num; ++i) {
		for (int j = l[i]; j <= r[i]; ++j) {
			sum[i] += a[j];
		}
	}
}

void pushdown(int x) {//下传
	for (int i = l[x]; i <= r[x]; ++i) {
		a[i] = (a[i] * mul[x] + tag[x]) % mod;
	}
	tag[x] = 0; mul[x] = 1;
}

void add(int x, int y, int k) {
	if (belong[x] == belong[y]) {
		pushdown(belong[x]);
		for (int i = x; i <= y; ++i) { a[i] = a[i] + k;  sum[belong[i]] = (sum[belong[i]] + k) % mod; }
	}
	else {
		pushdown(belong[x]);
		for (int i = x; i <= r[belong[x]]; ++i) { a[i] = a[i] + k;  sum[belong[i]] = (sum[belong[i]] + k) % mod; }
		pushdown(belong[y]);
		for (int i = l[belong[y]]; i <= y; ++i) { a[i] = a[i] + k;  sum[belong[i]] = (sum[belong[i]] + k) % mod; }
		for (int i = belong[x] + 1; i < belong[y]; ++i) { tag[i] += k; tag[i] %= mod; sum[i] = (sum[i] + k * len[i]) % mod; }
	}
}

void mu(int x, int y, int k) {
	if (belong[x] == belong[y]) {
		pushdown(belong[x]);
		for (int i = x; i <= y; ++i) { sum[belong[i]] = (sum[belong[i]] + (k - 1) * a[i]) % mod; a[i] = a[i] * k; }
	}
	else {
		pushdown(belong[x]);
		for (int i = x; i <= r[belong[x]]; ++i) { sum[belong[i]] = (sum[belong[i]] + (k - 1) * a[i]) % mod; a[i] = a[i] * k;}
		pushdown(belong[y]);
		for (int i = l[belong[y]]; i <= y; ++i) { sum[belong[i]] = (sum[belong[i]] + (k - 1) * a[i]) % mod; a[i] = a[i] * k;}
		for (int i = belong[x] + 1; i < belong[y]; ++i) {
			mul[i] = mul[i] * k % mod;
			tag[i] = tag[i] * k % mod;
			sum[i] = sum[i] * k % mod;
		}
	}
}

void summ(int x, int y) {
	ll ans = 0;
	if (belong[x] == belong[y]) {
		for (int i = x; i <= y; ++i) ans += (a[i] % mod * mul[belong[i]] % mod + tag[belong[i]]) % mod;
	}
	else {
		for (int i = x; i <= r[belong[x]]; ++i) 
			{ans += (a[i] * mul[belong[i]] + tag[belong[i]]) % mod;}
		for (int i = l[belong[y]]; i <= y; ++i)
			{ans += (a[i] * mul[belong[i]]+ tag[belong[i]]) % mod;}
		for (int i = belong[x] + 1; i < belong[y]; ++i) 
			ans = (ans+sum[i]) % mod;
	}
	ans = (ans + mod) % mod;
	printf("%lld\n", ans);
}

int main()
{
	for (int i = 1; i <= maxn; ++i) mul[i] = 1;
	n = read(), m = read(), mod = read();
	for (int i = 1; i <= n; ++i)  a[i]=read();
	build();
	for (int i = 1; i <= m; ++i) {
		int t;
		int x, y, k;
		t=read();
		if (t == 2) {
			x = read(), y = read(), k = read();
			add(x, y, k);//题上说是整数,所以大概可能为负
		}
		else if(t == 3) {
			x = read(), y = read();
			summ(x, y);
		}
		else {
			x = read(), y = read(), k = read();
			mu(x, y, k);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值