当前位置: 首页 > news >正文

A 找倍数 (线段树)

(“华讯杯”内蒙古自治区第十七届大学生程序设计竞赛 A题 找倍数)

题目描述

有一个下标从 1 到 n 的数列,需要进行 q 次操作。操作有两种类型:

  • 修改操作(类型1):将下标在区间 [l, r] 中的每一个数加上 x
    格式:1 l r x
  • 查询操作(类型2):求出下标在区间 [l, r] 内的数中有多少是 y 的倍数(保证 y 是 m 的因子)
    格式:2 l r y
输入格式:

第一行包含三个整数 n , q , m n, q, m n,q,m 1 ≤ n , q ≤ 100 , 000 , 1 ≤ m ≤ 50 1 \leq n, q \leq 100,000, 1 \leq m \leq 50 1n,q100,0001m50 ),分别表示数列长度、操作次数和常数 m m m

第二行包含 n n n 个用空格分隔的整数,表示数列的初始值 a i a_i ai 0 ≤ a i ≤ m 0 \leq a_i \leq m 0aim )。

接下来 q q q 行,每行描述一个操作:四个整数,第一个是操作类型(1 或 2),后三个是操作参数(含义如上)。

输出格式:

对于每个类型 2 的操作,输出一行整数,表示查询的结果。

输入样例:
5 6 10
1 2 4 6 8
2 1 5 2
1 1 5 1
2 3 5 2
2 1 3 2
1 5 5 1
2 1 5 10
输出样例:
4
0
1
1

思路

区间问题使用线段树维护:

m 的值不超过 50,因此因子 y 的取值只有少数几个。

每个线段树节点维护一个数组 cnt[MAXM],其中 cnt[i] 表示该节点对应区间内值 ≡ i (mod m) 的元素个数。

区间加法操作相当于对区间内所有数的模 m 结果进行平移((i + x) % m)。

查询时,直接累加所有 i ≡ 0 (mod y) 的 cnt[i] 值。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define pb push_back
#define pii pair<int, int>
#define FU(i, a, b) for (int i = (a); i <= (b); ++i)
#define FD(i, a, b) for (int i = (a); i >= (b); --i)
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 5, MAXN = maxn;
const int maxm = 50;
int n, m, q;
int a[maxn];
struct node {int lz = 0;int l, r;int cnt[maxm] = {};
} tr[4 * maxn];void pushup(int p) {for (int i = 0; i < maxm; i++) {tr[p].cnt[i] = tr[2 * p].cnt[i] + tr[2 * p + 1].cnt[i];}
}void apply(int p, int x) {x %= m;int tcnt[maxm] = {};for (int i = 0; i < m; i++) {int j = (i + x) % m;tcnt[j] += tr[p].cnt[i];}memcpy(tr[p].cnt, tcnt, sizeof(int) * m);tr[p].lz = (tr[p].lz + x) % m;
}void pushdown(int p) {if (tr[p].lz) {if (tr[p].l != tr[p].r) {apply(2 * p, tr[p].lz);apply(2 * p + 1, tr[p].lz);tr[p].lz = 0;}}
}void build(int p, int l, int r) {tr[p].l = l;tr[p].r = r;tr[p].lz = 0;memset(tr[p].cnt, 0, sizeof(tr[p].cnt));if (l == r) {tr[p].cnt[(a[l] % m)] = 1;return;}int mid = (l + r) / 2;build(2 * p, l, mid);build(2 * p + 1, mid + 1, r);pushup(p);
}void add(int p, int l, int r, int x) {if (x % m == 0)return;if (l <= tr[p].l && tr[p].r <= r) {apply(p, x);return;}pushdown(p);int mid = (tr[p].l + tr[p].r) / 2;if (mid >= l) {add(2 * p, l, r, x);}if (mid < r) {add(2 * p + 1, l, r, x);}pushup(p);
}int ask(int p, int l, int r, int y) {if (l <= tr[p].l && tr[p].r <= r) {int sum = 0;for (int i = 0; i < m; i += y) {sum += tr[p].cnt[i];}return sum;}pushdown(p);int mid = (tr[p].l + tr[p].r) / 2;int res = 0;if (mid >= l) {res += ask(2 * p, l, r, y);}if (mid < r) {res += ask(2 * p + 1, l, r, y);}return res;
}signed main() {
#ifndef ONLINE_JUDGEfreopen("../in.txt", "r", stdin);
#endifcin.tie(0)->ios::sync_with_stdio(0);cin >> n >> q >> m;FU(i, 1, n) { cin >> a[i]; }build(1, 1, n);while (q--) {int op, l, r, y;cin >> op >> l >> r >> y;if (op == 1) {add(1, l, r, y);} else {cout << ask(1, l, r, y) << endl;}}return 0;
}
http://www.xdnf.cn/news/966079.html

相关文章:

  • 凤凰双展翅之七七一五八九五隔位六二五
  • LeetCode 146.LRU缓存
  • Web应用压力测试详解
  • 力扣LFU460
  • FR4 中的色散如何真正影响传播延迟?
  • VSCode主题设计大赛
  • Deepin 25 安装字体
  • 若依使用RedisCache需要注意的事项
  • idea大量爆红问题解决
  • OpenGL学习20250610
  • Docker重启流程解析
  • MySQL中的CONVERT_TZ() 函数
  • C++ 智能指针实现原理
  • [一生一芯] 如何基于iSTA 分析时序
  • 3-存储系统
  • 【OpenCV】双相机结构光成像与图像交叉融合实现【C++篇】
  • 【Qt】Qt生成的exe依赖库与打包
  • 一天时间解决期末不挂科
  • 人工智能增强入侵检测系统以对抗高级持续性杀伤链
  • CTF show Web 红包题第六弹
  • 条件概率:AI大模型概率统计的基石
  • 第二讲 认识变量及数学运算符
  • 《广度优先搜索》题集
  • 一个n8n构建的能和LLM对话的Agent
  • mybatics
  • LCS4110R安全芯片防抄板原理
  • 黑马python(三)
  • 手写muduo网络库(三):事件分发器(Poller,EPollPoller实现)
  • java复习 07
  • C#设计模式