BZOJ 3110 [Zjoi2013]K大数查询

  O∧O http://www.lydsy.com/JudgeOnline/problem.php?id=3110

  首先对输入的操作1的数字c离散化。

  然后建一棵线段树,这个线段树中,li=a,ri=b这一位置存放 满足li<=c<=ri的的数字c们所对应线段树

  这些内层的线段树是根据区间来构造的,比如对于c∈(x,y)的线段树,在li=a,ri=b的位置记录了区间[a,b]中有多少c∈(x,y)的c。

  (思路来自某其他博客)

  

//http://www.lydsy.com/JudgeOnline/problem.php?id=3110

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N=100044;
const int M=N*256;

struct Input
{
	int op,a,b,c;
} input[55555];

int mp[N],lmp;
int root[N*4],lc[M],rc[M],lazy[M],tnum;
ll sum[M];
int n,m;

ll count(int id,int li,int ri,int L,int R)
{
	if(L<=li && ri<=R)
		return sum[id];
	ll ret=(min(R,ri)-max(L,li)+1)*lazy[id],mid=(li+ri)>>1;
	if(mid>=L)
		ret+=count(lc[id],li,mid,L,R);
	if(mid+1<=R)
		ret+=count(rc[id],mid+1,ri,L,R);
	return ret;
}

int query(int L,int R,ll K)
{
	int li=1,ri=n,mid,now=1;
	ll tmp;
	while(li!=ri)
	{
		mid=(li+ri)>>1;
		tmp=count(root[now*2+1],1,n,L,R);	//lc: now*2 (li~mid)  rc:now*2+1 (mid+1~ri)
		if(tmp<K)	//in the left part
		{
			ri=mid;
			now=now*2;
			K-=tmp;
		}
		else
		{
			li=mid+1;
			now=now*2+1;
		}
	}
	return li;
}

void modify(int &id,int li,int ri,int L,int R)
{
	int mid=(li+ri)>>1;
	if(!id) id=++tnum;
	if(L<=li && ri<=R)
	{
		sum[id]+=ri-li+1;
		++lazy[id];
		return ;
	}
	if(mid>=L)
		modify(lc[id],li,mid,L,R);
	if(mid+1<=R)
		modify(rc[id],mid+1,ri,L,R);
	sum[id]=sum[lc[id]]+sum[rc[id]]+lazy[id]*(ri-li+1);
}

void deal(int L,int R,int num)
{
	int li=1,ri=n,mid,now=1;
	while(li!=ri)
	{
		modify(root[now],1,n,L,R);
		mid=(li+ri)>>1;
		if(mid<num)	//choose the right child
		{
			li=mid+1;
			now=now*2+1;
		}
		else	//choose the left child
		{
			ri=mid;
			now=now*2;
		}
	}
	modify(root[now],1,n,L,R);
}

void solve(int op_num)
{
	int op,a,b,c,i;
	for(i=1;i<=op_num;i++)
	{
		op=input[i].op; a=input[i].a; b=input[i].b; c=input[i].c;
		if(op==1)	//update
			deal(a,b,c);
		else	//query
		{
			int ans=query(a,b,c);
			printf("%d\n",mp[ans]);
		}
	}
}

inline void read(int &ret)
{
    int k=0;
    char f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar() )
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar() )
        k=k*10+c-'0';
    ret=k*f;
}

void init(int op_num)
{
	int i,j;
	for(i=1;i<=op_num;i++)
	{
		read(input[i].op);
		read(input[i].a);
		read(input[i].b);
		read(input[i].c);
	}
	lmp=0;
	for(i=1;i<=op_num;i++)
		if(input[i].op==1)
			mp[++lmp]=input[i].c;
	sort(mp+1,mp+lmp+1);
	lmp=unique(mp+1,mp+lmp+1)-(mp+1);
	for(i=1;i<=op_num;i++)
		if(input[i].op==1)
			input[i].c=lower_bound(mp+1,mp+lmp+1,input[i].c)-mp;
}

int main()
{
	int i,j;
	scanf("%d%d",&n,&m);
	init(m);
	solve(m);
	return 0;
}

/*

2 5

1 1 2 -11

1 1 2 -22

2 1 1 2

2 1 1 1

2 1 2 3

*/

  

posted @ 2017-08-07 02:41  太阳星人FxxL  阅读(258)  评论(0编辑  收藏  举报