K大数查询[整体二分][线段树]

题目描述

有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c

如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

输入格式:

第一行N,M接下来M行,每行形如1 a b c或2 a b c

输出格式:

输出每个询问的结果

输入样例#1: 

2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3

输出样例#1: 

1
2
1

[整体二分模板]

#include<bits/stdc++.h>
#define N 100005
#define LL long long 
using namespace std;
int n,m,tot,sign;LL ans[N];
struct Query{int x,y,op,k,id;}q[N],lq[N],rq[N];
struct Tree{LL val,tag;}t[N<<1];
int read(){
	int cnt=0;char ch=0;
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
	return cnt;
}
void Pushup(int o){
	t[o].val=t[o<<1].val+t[o<<1|1].val;
}
void Pushdown(int o,int l,int r){
	if(t[o].tag){
		int mid=(l+r)>>1;
		t[o<<1].val+=(LL)t[o].tag*(mid-l+1);
		t[o<<1|1].val+=(LL)t[o].tag*(r-mid);
		t[o<<1].tag+=t[o].tag;
		t[o<<1|1].tag+=t[o].tag; 
		t[o].tag=0;
	}
}
void add(int o,int l,int r,int L,int R,int val){
	if(L<=l&&r<=R){
		t[o].val+=(LL)(r-l+1)*val,t[o].tag+=val;
		return;
	}
	Pushdown(o,l,r);
	int mid=(l+r)>>1;
	if(L<=mid) add(o<<1,l,mid,L,R,val);
	if(R>mid) add(o<<1|1,mid+1,r,L,R,val);
	Pushup(o); 
}
LL quary(int o,int l,int r,int L,int R){
	if(L<=l&&r<=R) return t[o].val;
	Pushdown(o,l,r);
	int mid=(l+r)>>1;LL ans=0;
	if(L<=mid) ans+=quary(o<<1,l,mid,L,R);
	if(R>mid) ans+=quary(o<<1|1,mid+1,r,L,R);
	return ans;
}
void Solve(int L,int R,int l,int r){
	if(l>r||L>R) return;
	if(l==r){
		for(int i=L;i<=R;i++)
			ans[q[i].id]=l;
		return;
	}
	int mid=(l+r)>>1,lcnt=0,rcnt=0;
	for(int i=L;i<=R;i++){
		if(q[i].op==1){
			if(q[i].k>mid){
				rq[++rcnt]=q[i];
				add(1,1,n,q[i].x,q[i].y,1);
			}
			else lq[++lcnt]=q[i];
		}
		else{
			LL tmp=quary(1,1,n,q[i].x,q[i].y);
			if(tmp>=q[i].k) rq[++rcnt]=q[i];
			else{
				q[i].k-=tmp,lq[++lcnt]=q[i];
			} 
		}
	}
	for(int i=L;i<=R;i++)
		if(q[i].op==1&&q[i].k>mid)
			add(1,1,n,q[i].x,q[i].y,-1);
	for(int i=1;i<=lcnt;i++) q[i+L-1]=lq[i];
	for(int i=1;i<=rcnt;i++) q[i+L+lcnt-1]=rq[i];
	Solve(L,L+lcnt-1,l,mid);
	Solve(L+lcnt,R,mid+1,r);
}
int main(){
	n=read(),m=read();
	while(m--){
		q[++tot].op=read(),q[tot].x=read(),q[tot].y=read(),q[tot].k=read();
		if(q[tot].op==2) q[tot].id=++sign;
	}
	Solve(1,tot,1,n);
	for(int i=1;i<=sign;i++){
		printf("%lld\n",ans[i]);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值