MnZn 10pts(从模板一来的)求调
查看原帖
MnZn 10pts(从模板一来的)求调
709447
tx774楼主2023/8/20 19:58
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5;
int n,m;
int a[N],b[N];
/*
将数据离散化,推荐使用C++的STL中的unique函数;
以离散化数组为基础,建一个全0的线段树,称作基础主席树;
对原数据中每一个[1,i]区间统计
有序地插入新节点
(题目中i每增加1就会多一个数,仅需对主席树对应的节点增加1即可)
对于查询[1,r][1,r]中第kk小值的操作
找到[1,r][1,r]对应的根节点
我们按照线段树的方法操作即可
(这个根节点及其子孙构成的必定是一颗线段树)。
*/
struct Persistent_segment_tree{
    int sumcnt;//节点数,插入节点用
    int root[N];//存根
    struct menber{
        int sum;//第i个线段树中某个区间sum表示a1-ai中数字在[l,r]范围内的个数
        int ls,rs;
    };menber node[N<<5];

    int build_node(int o)//新建节点&回传当前节点(copy node o)
    {
        sumcnt++;//先加后赋 
        node[sumcnt]=node[o];//全部信息都传到新节点
        node[sumcnt].sum=node[o].sum+1;
        return sumcnt;
    }

    int build_tree(int l, int r)//建o树,范围[l,r]&回传当前节点
    {
        int o=++sumcnt;//先加后赋 
        if(l==r)
        {
            node[o].sum=0;//建一个全0的线段树
            return o;
        }
        int mid=(l+r)>>1;
        node[o].ls=build_tree(l,mid);
        node[o].rs=build_tree(mid+1,r);
        return o;
    }

    int update(int father,int l,int r,int x)//回传当前节点 
    {
        int o=build_node(father);//更新就要新建节点 
        if(l==r)
        {
            return o;
        }
        //递归修改子区间
        int mid=(l+r)>>1;
        if(x<=mid) node[o].ls=update(node[father].ls,l,mid,x);
        else node[o].rs=update(node[father].rs,mid+1,r,x);       
        return o;

    }

    int query(int u,int v,int l,int r,int k)
    {
        if(l==r)
        {
            return b[l];
        }
        int mid=(l+r)>>1;
        int num=node[node[v].ls].sum-node[node[u].ls].sum;
//num=(1~r)树的左节点数字出现的次数-(1~(l-1))树的左节点数字出现的次数
//等于([l,r])树左儿子数字出现的次数 
        if(num>=k) return query(node[u].ls,node[v].ls,l,mid,k);
        else return query(node[u].ls,node[v].ls,mid+1,r,k-num);
        //右子树处找第x-num小的数字 
    }
} PST;

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;++i)
        cin>>a[i],b[i]=a[i];
    sort(b+1, b+1+n);
    int sumdiff=unique(b+1, b+1+n)-b-1;
    //离散化数组中不重复的数字的个数
    //unique把相邻元素的重复元素添加到容器末尾,而返回值是去重之后的尾地址
    PST.root[0]=PST.build_tree(1,sumdiff);  
    for(int i=1;i<=n;i++)
    {
        int t=lower_bound(b+1,b+1+sumdiff,a[i])-b;
        PST.root[i]=PST.update(PST.root[i-1],1,sumdiff,t);
    }
    for(int i=1,l,r,k;i<=m;++i)
    {
        cin>>l>>r>>k;
        cout<<PST.query(PST.root[l-1],PST.root[r],1,sumdiff,k)<<endl;
    }
    return 0;
}
2023/8/20 19:58
加载中...