SP3266 KQUERY - K-query

给定一个长度为n的序列a[1]到a[n]

q次询问:给定i,j,k,求出a[i]到a[j]中大于k的个数

主席树裸题,但是懒得写

刚开始写了个莫队+树状数组,复杂度是没问题的\(O(n\sqrt{q}logn)\),但是wa了,也懒得调了

然后还有种离线做法

将询问按\(k\)降序排序,对\(a\)降序排序

我们用一个指针\(l\),如果\(l\)没到头并且\(a[l] > k\),那么就往后移指针,并且把对应位置单点加\(1\),答案就转化为了区间查询和

因为\(l\)从头到尾最多移一次,所以时间复杂度\(O(nlogn)\)

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
const int N = 3e4;
const int M = 2e5;
#define zrt k << 1
#define yrt k << 1 | 1
using namespace std;
struct ad
{
    int id,v;
}a[N + 5];
struct node
{
    int l,r,k,id;
}q[M + 5];
int n,m,ans[M + 5],cnt;
int cmp1(ad x,ad y)
{
    return x.v > y.v;
}
int cmp2(node x,node y)
{
    return x.k > y.k;
}
struct dd
{
    int su,tag;
};
struct Seg
{
    dd s[N * 4 + 5];
    void pushup(int k)
    {
        s[k].su = s[zrt].su + s[yrt].su;
    }
    void add(int k,int l,int r,int x,int z)
    {
        if (l == r)
        {
            s[k].su += z;
            return;
        }
        int mid = l + r >> 1;
        if (x <= mid)
            add(zrt,l,mid,x,z);
        else
            add(yrt,mid + 1,r,x,z);
        pushup(k);
    }
    int query(int k,int l,int r,int x,int y)
    {
        if (l >= x && r <= y)
            return s[k].su;
        int mid = l + r >> 1;
        if (x > mid)
            return query(yrt,mid + 1,r,x,y);
        else
            if (y <= mid)
                return query(zrt,l,mid,x,y);
            else
                return query(zrt,l,mid,x,y) + query(yrt,mid + 1,r,x,y);
    }
}tree;
int main()
{
    scanf("%d",&n);
    for (int i = 1;i <= n;i++)
    {
        scanf("%d",&a[i].v);
        a[i].id = i;
    }
    scanf("%d",&m);
    for (int i = 1;i <= m;i++)
    {
        scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
        q[i].id = i;
    }
    sort(a + 1,a + n + 1,cmp1);
    sort(q + 1,q + m + 1,cmp2);
    int l = 1;
    for (int i = 1;i <= m;i++)
    {
        while (l <= n && a[l].v > q[i].k)
        {
            tree.add(1,1,n,a[l].id,1);
            l++;
        }
        ans[q[i].id] = tree.query(1,1,n,q[i].l,q[i].r);
    }
    for (int i = 1;i <= m;i++)
        printf("%d\n",ans[i]);
    return 0;
}
posted @ 2020-06-08 19:53  eee_hoho  阅读(39)  评论(0编辑  收藏  举报