1 条题解

  • 0
    @ 2025-8-24 21:36:12

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar communist
    Who Dare Wins !

    搬运于2025-08-24 21:36:12,当前版本为作者最后更新于2018-04-10 08:35:07,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    楼下各位大佬都用的排序和杨颙大定理,蒟蒻的我怎么也不会做(瑟瑟发抖),那么,就来一发主席树吧。

    我们知道线段树可以维护区间,平衡树可以维护值域

    那么,我们可以用线段树套平衡树来解决这个区间值域的问题

    线段树套平衡树~~(令人窒息的操作)~~

    好在权值线段树也可以维护值域,

    我们只要建n棵线段树维护前缀和,然后作差就好

    考虑空间限制,我们需要让这些线段树共用一些节点,再搞一搞离散化,其实这题的数据范围不用

    一颗主席树华丽登场

    时间复杂度O(nlogn),空间复杂度O(nlogn)

    上代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=5010;
    struct tree{
        int v,ls,rs;
    }a[15*maxn];
    int n,m,rt[maxn],cnt,mp[maxn],v[maxn],out[maxn];
    void insert(int pre,int cur,int p,int l,int r)    //插入
    {
        if(l==r)
        {
            a[cur].v=a[pre].v+1;
            return;
        }
        int m=(l+r)>>1;
        if(p<=m)
        {
            a[cur].ls=++cnt;    //新建节点
            a[cur].rs=a[pre].rs;    //共用节点
            insert(a[pre].ls,a[cur].ls,p,l,m);
        }
        else
        {
            a[cur].rs=++cnt;
            a[cur].ls=a[pre].ls;
            insert(a[pre].rs,a[cur].rs,p,m+1,r);
        }
        a[cur].v=a[a[cur].ls].v+a[a[cur].rs].v;    //push up
    }
    int kth(int x,int y,int k,int l,int r)    //查询k小值
    {
        if(l==r)
            return l;
        int m=(l+r)>>1;
        int num=a[a[y].ls].v-a[a[x].ls].v;    //前缀和
        if(num>=k)    //第k小在左子树
            return kth(a[x].ls,a[y].ls,k,l,m);
        else    //在右子树
            return kth(a[x].rs,a[y].rs,k-num,m+1,r);
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&v[i]);
            mp[i]=v[i];
        }
        sort(mp+1,mp+n+1);    //特色离散化
        cin>>m;
        for(int i=1;i<=n;i++)
        {
            v[i]=lower_bound(mp+1,mp+n+1,v[i])-mp;
            out[v[i]]=i;
            rt[i]=++cnt;
            insert(rt[i-1],rt[i],v[i],1,n);
        }
        for(int i=1;i<=m;i++)
        {
            int x,y,k;
            scanf("%d%d%d",&x,&y,&k);
            printf("%d\n",out[kth(rt[x-1],rt[y],k,1,n)]);
        }
        return 0;
    }
    
    • 1

    信息

    ID
    1263
    时间
    1000ms
    内存
    125MiB
    难度
    3
    标签
    (无)
    递交数
    0
    已通过
    0
    上传者