题意
给出一个序列,要求资瓷两个操作:
1 l r k表示把[l,r]中小于k的数都改成k
2 l r k x表示从小到大输出[l,r]中小于k的x个数,若数量不足则输出-1
n,q<=500000
分析
比赛的时候想到了分块做法,也就是对每块维护一个有序的数组,然后修改的话整块打标记,多出来的O(nlogn)暴力修改。查询的话把每块最小的那个和多出来的都扔进堆里面,然后每次找到堆顶再把其对应块中该元素的后缀仍进去就好了。
但略微算了一下,发现复杂度较高,于是不敢打。
正解:
考虑用线段树维护区间最小值和其所在位置。查询的话,用一个堆维护四元组(l,r,v,pos)。首先把整个区间(l,r,[l,r]最小值,所在位置)扔进堆中。每次取堆顶,若l < pos则加入(l,pos-1,v’,pos’);若r>pos则加入(pos+1,r,v’,pos’)。
时间复杂度O(nlog2n)
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=500005;
int n,m,a[N];
struct tree{
int mn,tag,pos;}t[N*5];
struct data
{
int l,r,v,pos;
bool operator < (const data &a) const
{
return v>a.v;
}
};
priority_queue<data> q;
vector<int> ans;
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<=