【树套树】bzoj3110 [Zjoi2013]K大数查询

题解很多,实现起来以外地简洁。内层的区间线段树上用了标记永久化。

#include<cstdio>
using namespace std;
#define N 50001
struct Node{int sumv,tag,lc,rc;}T[N*256];
int e;
int n,m;
void Update(int ql,int qr,int cur,int l,int r)
{
	if(ql<=l&&r<=qr)
	  ++T[cur].tag;
	else
	  {
	  	int m=(l+r>>1);
		if(ql<=m)
	  	  {
	  		if(!T[cur].lc) T[cur].lc=++e;
	  		Update(ql,qr,T[cur].lc,l,m);
		  }
		if(m<qr)
		  {
		  	if(!T[cur].rc) T[cur].rc=++e;
		  	Update(ql,qr,T[cur].rc,m+1,r);
		  }
	  }
	T[cur].sumv=T[T[cur].lc].sumv+T[T[cur].rc].sumv+T[cur].tag*(r-l+1);
}
int Query(int ql,int qr,int cur,int l,int r,int tag)
{
	if(ql<=l&&r<=qr) return T[cur].sumv+(r-l+1)*tag;
	int m=(l+r>>1),res=0;
	if(ql<=m) res+=Query(ql,qr,T[cur].lc,l,m,tag+T[cur].tag);
	if(m<qr) res+=Query(ql,qr,T[cur].rc,m+1,r,tag+T[cur].tag);
	return res;
}
int root[N<<2];
void Update_2D(int ql,int qr,int p,int rt,int l,int r)
{
	if(!root[rt]) root[rt]=++e;
	Update(ql,qr,root[rt],1,n);
	if(l==r) return;
	int m=(l+r>>1);
	if(p<=m) Update_2D(ql,qr,p,rt<<1,l,m);
	else Update_2D(ql,qr,p,rt<<1|1,m+1,r);
}
int Query_2D(int ql,int qr,int K,int rt,int l,int r)
{
	if(l==r) return l;
	int m=(l+r>>1);
	int Src=Query(ql,qr,root[rt<<1|1],1,n,0);
	if(Src>=K) return Query_2D(ql,qr,K,rt<<1|1,m+1,r);
	else return Query_2D(ql,qr,K-Src,rt<<1,l,m);
}
int main()
{
	int op,x,y,z;
	scanf("%d%d",&n,&m);
	for(;m;--m)
	  {
	  	scanf("%d%d%d%d",&op,&x,&y,&z);
	  	if(op==1) Update_2D(x,y,z,1,1,n);
	  	else printf("%d
",Query_2D(x,y,z,1,1,n));
	  }
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/4424220.html