P3332 [ZJOI2013]K大数查询

P3332 [ZJOI2013]K大数查询

题目描述

详见:P3332 [ZJOI2013]K大数查询

solution

整体二分+树状数组

code

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+50;
typedef long long ll;
ll n,m,Ans[MAXN],id[MAXN],quel[MAXN],quer[MAXN],f[MAXN];


inline ll read()
{
    ll x=0,f=1; char c=getchar();
    while (c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); }
    while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
    return x*f;
}
struct anode{ll id,opt,l,r,x,color; } a[MAXN];
int comparex(anode x,anode y) { return (x.opt<y.opt)||(x.opt==y.opt&&x.x<y.x); }
int compareid(anode x,anode y) { return x.id<y.id; }
struct Tree_Array
{
	ll tree[2][MAXN<<1];
	int lowbit(int x){ return x&(-x); }
	ll getans(int opt,ll x) { ll ans=0; while (x) ans+=tree[opt][x],x-=lowbit(x); return ans; }
	ll query(int l,int r) { return getans(0,r)*(r+1)-getans(0,l)*l-getans(1,r)+getans(1,l); }
	void change(int opt,int x,ll y) { while (x<=n) tree[opt][x]+=y,x+=lowbit(x); }
	void update(int l,int r,ll x) { change(0,l,x),change(1,l,x*l),change(0,r+1,-x),change(1,r+1,-x*(r+1)); }
} Tree;
void solve(int L,int R,int l,int r)
{
	if (l>r) return; 
	/*
	cout<<L<<" "<<R<<" "<<l<<" "<<r<<":";
	for (int i=l;i<=r;i++) cout<<" "<<id[i]; cout<<endl;
	*/
	if (L==R)
	{
		for (int i=l;i<=r;i++) Ans[id[i]]=L;
		return;
	}
	int mid=(L+R)>>1,numl=0,numr=0;
	for (int i=l;i<=r;i++)
	{
		if (a[id[i]].opt==1)
		{
			if (a[id[i]].color<=mid) quel[++numl]=id[i],Tree.update(a[id[i]].l,a[id[i]].r,1);
			else quer[++numr]=id[i];
		}
		else
		{
		    ll q=Tree.query(a[id[i]].l,a[id[i]].r);
			if (q>=a[id[i]].color) quel[++numl]=id[i];
			else quer[++numr]=id[i],a[id[i]].color-=q;
		}
	}
	for (int i=1;i<=numl;i++) 
	    if (a[quel[i]].opt==1) Tree.update(a[quel[i]].l,a[quel[i]].r,-1);
	
	for (int i=l;i<=l+numl-1;i++) id[i]=quel[i-l+1];
	for (int i=r-numr+1;i<=r;i++) id[i]=quer[i-r+numr];
	
	solve(L,mid,l,l+numl-1);
	solve(mid+1,R,r-numr+1,r);
}
int main()
{
	n=read(),m=read();
	ll p=0;
	for (int i=1;i<=m;i++) a[i]=(anode){i,read(),read(),read(),read(),0},id[i]=i;
	
	sort(a+1,a+m+1,comparex);
	a[0].x=a[1].x+1;
	for (int i=1;i<=m;i++) 
	    if (a[i].opt==1) a[i].color=a[i-1].color+(a[i].x!=a[i-1].x),p=max(p,a[i].color);
	    else a[i].color=a[i].x;
	for (int i=1;i<=m;i++)
	    if (a[i].opt==1) a[i].color=p-a[i].color+1,f[a[i].color]=a[i].x;
	sort(a+1,a+m+1,compareid);
	/*
	cout<<endl;
	for (int i=1;i<=m;i++) cout<<a[i].opt<<" "<<a[i].l<<" "<<a[i].r<<" "<<a[i].color<<endl;
	cout<<endl;
	*/
	solve(1,n*2+1,1,m);
	for (int i=1;i<=m;i++)
	    if (a[i].opt==2) printf("%lld\n",f[Ans[i]]);
	return 0;
}
/*
5 4
1 1 5 1
1 1 2 3
1 2 4 5
2 1 3 2

1
2
1
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值