Codeforces Round #602 (Div. 2) D: Optimal Subsequences 权值线段树

Codeforces #602 (Div. 2) D: Optimal Subsequences 权值线段树

链接:Optimal Subsequences
在这里插入图片描述在这里插入图片描述
题解:题目要求sum最大且字典序最小。在输入数据的时候对每个数 x x 标记一个下标 i d id ,用一个结构体数组 p p 存储,按数值从大到小,下标从小到大排序,那么当 k k 一定的时候,组成 s u m sum 值最大的 k k 个数一定是数组 p p 的前 k k 个数,我们可以利用线段树维护前 k k 个数的下标 i d id 在区间 [ l , r ] [l,r] 出现的次数(单点更新求和),保存在 s u m sum 数组里,查询的时侯当 k k 一定的情况下,查询第 p o s pos 大的下标 i d id ,然后根据 i d id 在原数组 a a 中访问值,存入 a n s ans 数组中。

代码:

#include<bits/stdc++.h>
 
using namespace std;
typedef long long LL;
const int maxn = 2e5+100;
 
struct node
{
    int x;
    int id;
} p[maxn];
vector<node > g[maxn];
int a[maxn];
bool cmp(node a, node b)
{
    if(a.x==b.x)
    {
        return a.id<b.id;
    }
    return a.x>b.x;
}
int sum[maxn*4];
void build(int l, int r, int son)//建树
{
    sum[son] = 0;
    if(l==r)return ;
    int mid = (l+r)>>1;
    build(l,mid,son*2);
    build(mid+1, r, son*2+1);
}
 
void update(int l, int r, int son, int x)//更新区间和
{
    if(l==r)
    {
        sum[son]++;
        return ;
    }
    int mid = (l+r)>>1;
    if(x<=mid)
    {
        update(l,mid,son*2,x);
    }
    else
    {
        update(mid+1,r,son*2+1,x);
    }
    sum[son] = sum[son*2]+sum[son*2+1];
}
 
int query(int l, int r,int son, int x)//查询第x大的值
{
    if(l==r)return l;
    int mid = (l+r)>>1;
    if(x<=sum[2*son])
        return query(l,mid,son*2,x);
    else
        return query(mid+1,r,son*2+1,x-sum[2*son]);
}
int ans[maxn];
 
int main()
{
    int n,m;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        p[i].id = i;p[i].x = a[i];//匹配下标,用于排序
    }
    sort(p+1, p+n+1, cmp);
    scanf("%d",&m);
    int k;
    node pos;
    for(int i = 1; i <= m; i++)
    {
        scanf("%d%d", &k, &pos.x);
        pos.id = i;//匹配下标,用于查询保存
        g[k].push_back(pos);//保存k个数的时候,需要查询的位置
    }
    build(1,n,1);
    for(int i = 1; i <= n; i++)
    {
        update(1,n,1,p[i].id);//更新前k个数
        for(int j = 0; j < g[i].size(); j++)//查询当前k个数下需要查询的位置
        {
            int s = query(1,n,1,g[i][j].x);//查询pos位置的值
            ans[g[i][j].id] = a[s];//根据原数组访问答案,存入ans
        }
    }
    for(int i = 1; i <= m; i++)
    {
        printf("%d\n", ans[i]);
    }
 
    return 0;
}

更新于11/26 18:12

发布了27 篇原创文章 · 获赞 13 · 访问量 1700

猜你喜欢

转载自blog.csdn.net/weixin_43855330/article/details/103246580