No Luck -- 主席树

https://codeforces.com/gym/103388/problem/N

题目理解:

就是给了一个 \(3 \cdot 10^5\)的数组,大概 $ 3 \cdot 10^5$ 个查询,每次询问某个区间内数组中大于等于某个数的数有几个。

AC代码

#include<bits/stdc++.h>
using namespace std;

#define ll long long
const int maxn = 300005;
int n,q,tot,rt[maxn],a[maxn];
struct chairman_tree
{
    int son[2],siz;
} node[maxn*50];
void build(int &rt,int l,int r)
{
    rt = ++tot;
    if(l==r) return;
    int mid = (l + r) >> 1;
    build(node[rt].son[0],l,mid);
    build(node[rt].son[1],mid+1,r);
}
void update(int &rt,int last,int l,int r,int val)
{
    node[rt=++tot] = node[last];
    ++node[rt].siz;
    if(l==r) return;
    int mid = (l + r) >> 1;
    if(val<=mid) update(node[rt].son[0],node[last].son[0],l,mid,val);
    else update(node[rt].son[1],node[last].son[1],mid+1,r,val);
}
int query(int rt1,int rt2,int l,int r,int k)  //询问 rt2-rt1所维护的区间内 大于等于k的数的数量
{
    if(l==r) return l >= k ? node[rt2].siz-node[rt1].siz : 0;
    int mid = (l+r) >> 1;
    if(mid>=k) return node[node[rt2].son[1]].siz-node[node[rt1].son[1]].siz+
        query(node[rt1].son[0],node[rt2].son[0],l,mid,k); //右子树的大小全部加上,继续询问左子树
    else return query(node[rt1].son[1],node[rt2].son[1],mid+1,r,k); //继续询问右子树
}

signed main()
{
    scanf("%d %d",&n,&q);
    build(rt[0],0,100000); //在数据范围内建立权值线段树
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&a[i]);
        update(rt[i],rt[i-1],0,100000,a[i]);  //插入
    }
    int m,p,f;
    for(int i=1;i<=q;++i)
    {
        scanf("%d %d %d",&m,&p,&f);
        if(a[m]>=p) puts("0");
        else{
            int l = m + 1,r = m + f;
            printf("%d\n",query(rt[l-1],rt[r],0,100000,p));
        }
    }

    return 0;
}


posted @ 2022-02-16 11:47  HIVM  阅读(73)  评论(0编辑  收藏  举报