P3332 [ZJOI2013]K大数查询(整体二分做法)

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3332 [ZJOI2013]K大数查询(整体二分做法)相关的知识,希望对你有一定的参考价值。

P3332 [ZJOI2013]K大数查询

题意:

在这里插入图片描述

题解:

利用整体二分来做,这个题和P3834 【模板】可持久化线段树 2的区别在于本题的修改是区间修改,所以将里面的树状数组改成线段树就行,区间修改+区间查询
但是不知道为什么我调了一阵子也不对。。人傻了

代码:

自己写的代码还没调出:

#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b)
typedef long long ll;
using namespace std;

inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
   return s*w;
}
const int maxn=5e4+9;
struct node{
	int op,x,y;
	ll k;
	int id;
}q[maxn],q1[maxn],q2[maxn];
ll ans[maxn];
struct tree{
	int l,r;
	ll sum;
	ll lazy;
}tr[maxn<<2];
void pushup(int root){
	tr[root].sum=tr[root<<1].sum+tr[root<<1|1].sum;
}
void cal(int root,ll x)
{
	tr[root].sum=1ll*(tr[root].r-tr[root].l+1)*x;
	tr[root].lazy+=x;
}
void pushdown(int root){
	cal(root<<1,tr[root].lazy);
	cal(root<<1|1,tr[root].lazy);
	tr[root].lazy=0;
}
void build(int root,int l,int r)
{
	tr[root].l=l;
	tr[root].r=r;
	if(l==r)
	{
		tr[root].sum=0;
		tr[root].lazy=0;
		return; 
	}
	int mid=l+r>>1;
	build(root<<1,l,mid);
	build(root<<1|1,mid+1,r);
	pushup(root);
}
void update(int root,int l,int r,ll x){
	if(tr[root].r<l||tr[root].l>r)return ;
	if(tr[root].l>=l&&tr[root].r<=r)
	{
		cal(root,x);
		return ;
	}
	if(tr[root].lazy)pushdown(root);
	update(root<<1,l,r,x);
	update(root<<1|1,l,r,x);
	pushup(root);
}
ll query(int root,int l,int r)
{
	if(tr[root].r<l||tr[root].l>r)return 0;
	if(tr[root].l>=l&&tr[root].r<=r)
	{
		return tr[root].sum;
	}
	if(tr[root].lazy)pushdown(root);
	return query(root<<1,l,r)+query(root<<1|1,l,r);
}

void solve(int ql,int qr,ll L,ll R)
{
	//printf("ql=%d qr=%d L=%d R=%d\\n",ql,qr,L,R);
	if(ql>qr||L>R)return ;
	if(L==R)
	{
		for(int i=ql;i<=qr;i++)
			if(q[i].op==2)
				ans[q[i].id]=L;
		return ;
	}
	int len1=0,len2=0;
	ll mid=L+R>>1;
	for(int i=ql;i<=qr;i++)
	{
		if(q[i].op==1)//添加 
		{
			if(q[i].k<=mid)//放在右侧 
			{
				q2[++len2]=q[i];
			}
			else
			{
				update(1,q[i].x,q[i].y,1);
				q1[++len1]=q[i];
			} 
		}
		else //查询 
		{
			ll tmp=query(1,q[i].x,q[i].y);
			if(tmp>=q[i].k)
			{
				q1[++len2]=q[i];
			}
			else 
			{
				q[i].k-=tmp;
				q2[++len2]=q[i];
			}
		}
	}
	for(int i=1;i<=len1;i++)
	{
		if(q[i].op==1&&q[i].k>mid)update(1,q[i].x,q[i].y,-1);
	}
	
	for(int i=1;i<=len1;i++)q[ql+i-1]=q1[i];
	for(int i=1;i<=len2;i++)q[ql+len1+i-1]=q2[i];
	solve(ql,ql+len1-1,L,mid);
	solve(ql+len1,qr,mid+1,R);
}
int main()
{
	int n,m;
	cin>>n>>m;
	int tot=0;
	for(int i=1;i<=m;i++){
		int op,l,r;
		ll c;
		cin>>op>>l>>r>>c;
		if(op==1)//添加操作 
			q[i]=(node){op,l,r,c};
		if(op==2)//查询 
			q[i]=(node){op,l,r,c,++tot};
	}
	build(1,1,n); 
	solve(1,m,-n,n);
	for(int i=1;i<=tot;i++)
	{
		cout<<ans[i]<<endl;
	}
	return 0;
}

别人的AC的代码(和我写的风格很像):

#include <bits/stdc++.h>
using namespace std;
#define debug(...) fprintf(stderr,__VA_ARGS__)
typedef long long ll;
const int MAXN=200010;
const ll INF=2e18;
struct seg{
	int l,r;
	ll add,sum;
}t[MAXN<<2];
void pushup(int x){
	t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
}
void pushdown(int x){
	if (!t[x].add) return;
	int l=t[x].l,r=t[x].r,mid=(l+r)>>1;
	t[x<<1].add+=t[x].add;
	t[x<<1|1].add+=t[x].add;
	t[x<<1].sum+=t[x].add*(mid-l+1);
	t[x<<1|1].sum+=t[x].add*(r-mid);
	t[x].add=0;
}
void build(int x,int l,int r){
	t[x]=(seg){l,r,0,0};
	if (l==r)
		return;
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	pushup(x);
}
void update(int x,int ql,int qr,ll v){
	int l=t[x].l,r=t[x].r;
	if (ql<=l&&r<=qr){
		t[x].add+=v;
		t[x].sum+=v*(r-l+1);
		return;
	}
	pushdown(x);
	int mid=(l+r)>>1;
	if (ql<=mid) update(x<<1,ql,qr,v);
	if (mid<qr) update(x<<1|1,ql,qr,v);
	pushup(x);
}
ll query(int x,int ql,int qr){
	int l=t[x].l,r=t[x].r;
	if (ql<=l&&r<=qr) return t[x].sum;
	pushdown(x);
	int mid=(l+r)>>1;ll res=0;
	if (ql<=mid) res+=query(x<<1,ql,qr);
	if (mid<qr) res+=query(x<<1|1,ql,qr);
	return res;
}
ll ans[MAXN];
int n,m;
struct event{
	int opt,x,y;ll v;int id;
	void print(){
		debug("%d %d %d %lld\\n",opt,x,y,v);
	}
}q[MAXN],q1[MAXN],q2[MAXN];
void solve(ll l,ll r,int ql,int qr){
	if (ql>qr||l>r) return;
	if (l==r){
		for (int i=ql;i<=qr;i++)
			if (q[i].opt==2) ans[q[i].id]=l;
		return;
	}
	ll mid=(l+r)>>1;
	int cnt1=0,cnt2=0;
	for (int i=ql;i<=qr;i++){
		if (q[i].opt==1){
			if (q[i].v>mid){
				update(1,q[i].x,q[i].y,1);
				q1[++cnt1]=q[i];
			}else
				q2[++cnt2]=q[i];
		}else{
			ll tmp=query(1,q[i].x,q[i].y);
			if (tmp>=q[i].v)
				q1[++cnt1]=q[i];
			else{
				q[i].v-=tmp;
				q2[++cnt2]=q[i];
			}
		}
	}
	for (int i=1;i<=cnt1;i++)
		if (q1[i].opt==1&&q1[i].v>mid) update(1,q1[i].x,q1[i].y,-1);
	
	for (int i=ql;i<ql+cnt1;i++)
		q[i]=q1[i-ql+1];
	for (int i=ql+cnt1;i<=qr;i++)
		q[i]=q2[i-ql-cnt1+1];
	solve(mid+1,r,ql,ql+cnt1-1);
	solve(l,mid,ql+cnt1,qr);
}
int main(){
	scanf("%d%d",洛谷 P3332 [ZJOI2013]K大数查询 || bzoj3110

P3332 [ZJOI2013]K大数查询

bzoj 3110 [Zjoi2013]K大数查询 整体二分

BZOJ 3110 [Zjoi2013]K大数查询 ——整体二分

BZOJ 3110:[Zjoi2013]K大数查询(整体二分)

[ZJOI2013]K大数查询——整体二分