Codeforces #602 (Div. 2) D: Optimal Subsequences 权值线段树
链接:Optimal Subsequences
题解:题目要求sum最大且字典序最小。在输入数据的时候对每个数
标记一个下标
,用一个结构体数组
存储,按数值从大到小,下标从小到大排序,那么当
一定的时候,组成
值最大的
个数一定是数组
的前
个数,我们可以利用线段树维护前
个数的下标
在区间
出现的次数(单点更新求和),保存在
数组里,查询的时侯当
一定的情况下,查询第
大的下标
,然后根据
在原数组
中访问值,存入
数组中。
代码:
#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