query 线段树 + 区间排序
Posted echozqn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了query 线段树 + 区间排序相关的知识,希望对你有一定的参考价值。
https://nanti.jisuanke.com/t/41391
这个题目没有很难想,比较暴力,但是要会算复杂度,不会算复杂度,就会觉得自己的算法会超时,实际上不会。
这个题目就是直接暴力求出每一个数的在1e5以内的所有的约数和倍数,然后更新,就像之前写过的E - No Pain No Game 线段树 离线处理 区间排序 一样
算一下复杂度,调和级数要用两次,一次来求约数一次来求倍数,复杂度都是n*logn 所以平均下来每一个的约数大约就是logn
因为有个两倍的关系所以就是2*logn
线段树的复杂度,每次更新是logn ,要遍历一次
所以总的复杂度就是2*n*logn*logn,这个肯定不会超时的。
#include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <algorithm> #include <iostream> #define inf 0x3f3f3f3f using namespace std; const int maxn = 1e5 + 10; typedef long long ll; vector<int>num[maxn]; int a[maxn], vis[maxn], c[maxn], ans[maxn]; int n, m; struct node int l, r, id; node(int l=0,int r=0,int id=0):l(l),r(r),id(id) ex[maxn]; bool cmp(node a,node b) return a.r < b.r; int lowbit(int x) return x & (-x); void update(int x,int k) while (x <= n) c[x] += k; x += lowbit(x); int getsum(int x) int ans = 0; while (x > 0) ans += c[x]; x -= lowbit(x); return ans; int main() for (int i = 1; i < maxn; ++i) for (int j = 2*i; j < maxn; j += i) num[j].push_back(i);//先把每个数的因子有哪些打个表,由调和级数可知复杂度为o(nlog n) for (int i = 1; i < maxn; ++i) for (int j = 2 * i; j < maxn; j += i) num[i].push_back(j); scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= m; i++) int l, r; scanf("%d%d", &l, &r); ex[i] = node(l, r, i); memset(vis, -1, sizeof(vis)); sort(ex + 1, ex + 1 + m, cmp); int now = 1; for (int i = 1; i <= n; i++) int x = a[i]; for (int j = 0; j < num[x].size(); j++) int y = num[x][j]; if (vis[y] != -1) update(vis[y], 1); vis[x] = i; while (now <= m && i == ex[now].r) int res = getsum(ex[now].r) - getsum(ex[now].l - 1); ans[ex[now].id] = res; now++; for (int i = 1; i <= m; i++) printf("%d\\n", ans[i]); return 0;
以上是关于query 线段树 + 区间排序的主要内容,如果未能解决你的问题,请参考以下文章
CF911G Mass Change Queries (线段树区间 合并)
HDU 4027 Can you answer these queries?(线段树)
HDU4027 Can you answer these queries? —— 线段树 区间修改