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;
View Code

 

以上是关于query 线段树 + 区间排序的主要内容,如果未能解决你的问题,请参考以下文章

CF911G Mass Change Queries (线段树区间 合并)

871F.MEX Queries(线段树)

HDU 4027 Can you answer these queries?(线段树)

HDU4027 Can you answer these queries? —— 线段树 区间修改

HDU - 4027 Can you answer these queries? (线段树)

HDU-Can you answer these queries? (线段树+区间修改)