线段树维护区间前k小
线段树维护区间前k小

$ solution: $
觉得超级钢琴太麻烦?在这里线段树提供一条龙服务 。
咳咳,开始讲正题!这道题我们有一个和超级钢琴复杂度一样 $ O(\sum x\times logn)~ $ 的做法。因为线段数支持动态维护最小值,而取 $ max $ 操作我们可以用线段树的 $ lazytag $ 实现(不懂可以看看代码里的标记下传和区间修改)。所以我们主要目的就是输出区间前 $ x $ 小,这个其实我们可以用线段树的单点修改完成!
我们在区间 $ [l,r] $ 里面找最小值,假设其下标为 $ k $ 我们记录它的位置和它的权值。然后我们暂时将这个位置在线段树上用单点修改操作改成 $ inf $ ,这样我们就不会再将这个位置作为最小值。然后我们再在 $ [l,r] $ 中找一个最小值,这时我们可以找到另一个位置 $ k_2 $ ,然后重复给它变成 $ inf $ 的操作,并记录它的位置和权值。这样不断循环,当我们找完所有的区间前 $ x $ 小后。我们再用线段树的单点修改操作,将线段树上对应位置的值改回来!然后这题就做完了!
注意每一个最小值我们都要花 $ log $ 的时间查找,更改为 $ inf $ ,最后再改回来。 复杂度中有一定常数,但是算法只用了线段树,没有其它数据结构鱼龙混杂,跑起来效果还不错,当然重点是码量小一些!
$ code: $
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define rg register int
#define zuo k<<1,l,mid
#define you k<<1|1,mid+1,r
#define midd int mid=(l+r)>>1
#define pushd push(k,k<<1,k<<1|1)
using namespace std;
int n,m;
int x,y,v,t,sx,sv;
int as[500005];
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
}
struct su{
int da,id;
inline void min(const su a){
if(a.da<da){da=a.da;id=a.id;}
}
}a[500005];
struct tree{
int da[500005<<4];
int lz[500005<<4];
inline void build(int k,int l,int r){ //建树
if(l==r){da[k]=qr(); return ;}
midd; build(zuo); build(you);
da[k]=min(da[k<<1],da[k<<1|1]);
}
inline void push(int k,int l,int r){ //下传标记
if(lz[k]>da[l]){
da[l]=max(da[l],lz[k]);
lz[l]=max(lz[l],lz[k]);
}
if(lz[k]>da[r]){
da[r]=max(da[r],lz[k]);
lz[r]=max(lz[r],lz[k]);
} lz[k]=0;
}
inline void add1(int k,int l,int r){ //区间取max
if(x<=l&&r<=y){
if(da[k]>=v)return ; //权值只增不降
da[k]=max(da[k],v);
lz[k]=max(lz[k],v);
return ;
}if(lz[k])pushd; midd;
if(x<=mid)add1(zuo);
if(y>mid) add1(you);
da[k]=min(da[k<<1],da[k<<1|1]);
}
inline void add2(int k,int l,int r){ //单点修改权值
if(l==r){da[k]=sv; return ;}
if(lz[k])pushd; midd;
if(sx<=mid) add2(zuo);
else add2(you);
da[k]=min(da[k<<1],da[k<<1|1]);
}
inline su ask(int k,int l,int r){ //询问区间里的最小值信息
if(l==r)return su{da[k],l};
if(lz[k])pushd; midd;
if(x<=l&&r<=y){ //注意我们要精确的找到最小值位置
if(da[k<<1]==da[k])return ask(zuo);
else return ask(you);
}
register su res; res.da=1e9; res.id=1001;
if(x<=mid)res=ask(zuo);
if(y>mid) res.min(ask(you));
return res;
}
}tr;
int main(){
n=qr(); tr.build(1,1,n); m=qr();
for(rg i=1;i<=m;++i){
rg f=qr(); x=qr(); y=qr(); v=qr();
if(f==1){ //区间修改
tr.add1(1,1,n);
} else{
t=qr(); //
for(rg j=1;j<=t;++j){
a[j]=tr.ask(1,1,n); //读取最小值位置及权值
if(a[j].da>=v){t=j;break;} //不符合题意
sx=a[j].id; sv=1e9; //让最小值消失
tr.add2(1,1,n); //让之前的最小值不再被选中
}
if(a[t].da>=v) printf("-1");
else for(rg j=1;j<=t;++j) printf("%d ",a[j].da);
for(rg j=1;j<=t;++j){
sx=a[j].id; sv=a[j].da; //将之前改的变回原值
tr.add2(1,1,n);
}puts("");
}
}
return 0;
}
线段树维护区间前k小的更多相关文章
- 主席树--动态区间第k小
主席树--动态区间第\(k\)小 模板题在这里洛谷2617. 先对几个问题做一个总结: 阅读本文需要有主席树的基础,也就是通过区间kth的模板题. 静态整体kth: sort一下找第k小,时间复杂度\ ...
- [csu/coj 1080]划分树求区间前k大数和
题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数 ...
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- A - 低阶入门膜法 - K-th Number (主席树查询区间第k小)
题目链接:https://cn.vjudge.net/contest/284294#problem/A 题目大意:主席树查询区间第k小. 具体思路:主席树入门. AC代码: #include<i ...
- HDU 5919 - Sequence II (2016CCPC长春) 主席树 (区间第K小+区间不同值个数)
HDU 5919 题意: 动态处理一个序列的区间问题,对于一个给定序列,每次输入区间的左端点和右端点,输出这个区间中:每个数字第一次出现的位子留下, 输出这些位子中最中间的那个,就是(len+1)/2 ...
- Can you answer these queries V SPOJ - GSS5 (分类讨论+线段树维护区间最大子段和)
recursion有一个整数序列a[n].现在recursion有m次询问,每次她想知道Max { A[i]+A[i+1]+...+A[j] ; x1 <= i <= y1 , x2 &l ...
- CodeForces - 587E[线段树+线性基+差分] ->(线段树维护区间合并线性基)
题意:给你一个数组,有两种操作,一种区间xor一个值,一个是查询区间xor的结果的种类数 做法一:对于一个给定的区间,我们可以通过求解线性基的方式求出结果的种类数,而现在只不过将其放在线树上维护区间线 ...
- hdu_5726_GCD(线段树维护区间+预处理)
题目链接:hdu_5726_GCD 题意: 给你n个数(n<=1e5)然后m个询问(m<=1e5),每个询问一个区间,问你这个区间的GCD是多少,并且输出从1到n有多少个区间的GCD和这个 ...
- 滑动窗口(poj,线段树维护区间最值)
题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...
随机推荐
- C# Console.WriteLine堵塞进程
最近在项目中控制台为了调试使用Console.WriteLine(),发现在高并发的情况下会出现假锁状态,断点调试发现卡在Console.WriteLine那.需要进行一个键盘输入才可以继续. 关于C ...
- Eclipse与Tomcat
新进一个Web项目,有些小坎坷,于是引发了对于Eclipse和Tomcat的配置关系的思考. 首先提及一点当年的观点:Tomcat是一个容器,所有的功能都是以插件的形式放入其中:比如tomcat就是o ...
- win10安装Tensorflow1.9GPU版本
前言 看到DateWhale出了一篇安装教程(微信公众号DateWhale),决定体验一下Tensorflow1.9的GPU版本..其实一开始装的是2.0,但是tf.Session()就报错了,说是2 ...
- 爬虫二之Requests
requests 实例引入 import requests response = requests.get('https://www.baidu.com') response.status_code ...
- 第五周课程总结&试验报告(三
实验三 String类的应用 实验目的 掌握类String类的使用: 学会使用JDK帮助文档: 实验内容 1.已知字符串:"this is a test of java".按要求执 ...
- C/C++ 内存模型
C分为四个区:堆,栈,静态全局变量区,常量区 C++内存分为5个区域(堆栈全常代 ): 堆 heap : 由new分配的内存块,其释放编译器不去管,由我们程序自己控制(一个new对应一个delete) ...
- ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
参考来源:https://blog.csdn.net/yuxinha11/article/details/80090197 ENGINE=InnoDB不是默认就是这个引擎吗?——是的,如果不写也是ok ...
- 1、Java语言概述与开发环境——JDK JRE JVM理解
一.理解概念: 1.JDK(Java Development Kit Java开发工具包) JDK是提供给Java开发人员使用的,其中包含Java的开发工具,也包括JRE,所以安装了JDK,就不用单独 ...
- 使用redis+flask维护动态代理池
在进行网络爬虫时,会经常有封ip的现象.可以使用代理池来进行代理ip的处理. 代理池的要求:多站抓取,异步检测.定时筛选,持续更新.提供接口,易于提取. 代理池架构:获取器,过滤器,代理队列,定时检测 ...
- linux查找进程id和杀死进程以及查看内存??
ps 命令用于查看当前正在运行的进程 ps ax : 显示当前系统进程的列表 ps aux : 显示当前系统进程详细列表以及进程用户 -e 显示所有进程,环境变量 此参数的效果和指定"A&q ...