BZOJ 3110:K大数查询

10 篇文章 0 订阅
2 篇文章 0 订阅

整体二分题,很好理解,就是将查询区间和查询值区间进行整体二分。

#include<cstdio>
using namespace std;

#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b

typedef long long ll;
const  int maxn=50000+100;

ll bit[maxn][2];
int vis[maxn][2];
int tot;
int n,m;

inline int lowbit(int x){
	
	return x&(-x);
}

inline void update(int x,int ind,int v){

	while(x<=n){
		
		if(vis[x][ind]!=tot){
			
			vis[x][ind]=tot;
			bit[x][ind]=0;
		}
		bit[x][ind]+=(ll)v;
		x+=lowbit(x);
	}
}

inline void Add(int x,int y){
	
	update(x,0,1);
	update(y+1,0,-1);
	update(x,1,x);
	update(y+1,1,-(y+1));
}

inline ll getSum(int x,int ind){
	
	ll sum=0;
	while(x>0){
		
		if(vis[x][ind]==tot) sum+=bit[x][ind];
		x-=lowbit(x);
	}
	return sum;
} 

inline ll get_Sum(int x,int y){
	
	ll sum=0;
	sum=(ll)(y+1)*getSum(y,0)-getSum(y,1)-(ll)x*getSum(x-1,0)+getSum(x-1,1);
	return sum;
}

int ans[maxn];
int tmp[maxn][2];
int Id[maxn];
struct Node{
	int type;
    int x,y;
	int c;	
}node[maxn];

void Bin(int l,int r,int L,int R){
	
	if(l>r) return ;
	int mid=(L+R)>>1;
	if(L==R){
		
		for(int i=l;i<=r;i++) if(node[Id[i]].type==2) ans[Id[i]]=mid;
		return;
	}
	tmp[0][0]=tmp[0][1]=0;
	tot++;
	for(int i=l;i<=r;i++){
		
		
		int tmpe=Id[i];
		if(node[tmpe].type==1){
			
			if(node[tmpe].c<=mid){
				
				tmp[++tmp[0][0]][0]=tmpe; 
			}
			else{
				
				tmp[++tmp[0][1]][1]=tmpe;
				Add(node[tmpe].x,node[tmpe].y);
			}
		}
		else{
			
			ll cnt=get_Sum(node[tmpe].x,node[tmpe].y);
			if(cnt<node[tmpe].c){
				
				node[tmpe].c-=cnt;
				tmp[++tmp[0][0]][0]=tmpe;
			} 
			else{
				
				tmp[++tmp[0][1]][1]=tmpe;
			}
		}
	}
	int t1=l+tmp[0][0]-1;
	int t2=l;
	for(int i=1;i<=tmp[0][0];i++) Id[t2++]=tmp[i][0];
	for(int i=1;i<=tmp[0][1];i++) Id[t2++]=tmp[i][1];
	Bin(l,t1,L,mid);
	Bin(t1+1,r,mid+1,R); 
	
}

int main(){
	
	scanf("%d%d",&n,&m);
	int Max=-1e9;
	int Min=1e9;
	for(int i=1;i<=m;i++){
		
		scanf("%d%d%d%d",&node[i].type,&node[i].x,&node[i].y,&node[i].c);
		Id[i]=i;
		if(node[i].type==1){
			
			Max=max(Max,node[i].c);
			Min=min(Min,node[i].c); 
		}
	}
	Bin(1,m,Min,Max);
	for(int i=1;i<=m;i++) if(node[i].type==2) printf("%d\n",ans[i]);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ITKaven

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

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

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

打赏作者

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

抵扣说明:

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

余额充值