BZOJ3110 JZOI2013 K大数查询 线段树套线段树

权值线段树套区间线段树

外层的权值线段树中每个节点如果维护[L,R]这个区间,那么该节点所对应的线段树维护的就是[L,R]这些数在每个区间里出现了几次,也就是说如果外层线段树的某个节点维护[L,R],其所对应的内层线段树中某个节点[l,r]维护的值就是[L,R]这些数在[l,r]这个区间中出现的次数。

最后吐槽一下动态内存+指针版线段树MLE……尼玛我写指针版完全习惯了根本就不会写数组版了QAQ,自己拿数据一个一个对拍了一下程序本身是没问题的。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=50000+2;
typedef struct NODE1{
	int c,l,r,add;
	NODE1 *lchild,*rchild;
	NODE1(){}
	NODE1(int _l,int _r):l(_l),r(_r),c(0),add(0),lchild(0),rchild(0){}
} *TREE1;
typedef struct NODE2{
	 int l,r;
	 TREE1 root;
	 NODE2 *lchild,*rchild;
	 NODE2(){}
	 NODE2(int _l,int _r):l(_l),r(_r),root(0){}
} *TREE2;
TREE2 root;
int N,M;

void Build2(TREE2 &x,int l,int r){
	x=new NODE2(l,r);
	if(l==r) return;

	int m=(l+r)>>1;
	Build2(x->lchild,l,m),Build2(x->rchild,m+1,r);
}

void Pushup(TREE1 &x){
	x->c=0;
	if(x->lchild) x->c+=x->lchild->c;
	if(x->rchild) x->c+=x->rchild->c;
}

void Pushdown(TREE1 &x,int m){
	if(x->add && x->l!=x->r){
        if(!x->lchild) x->lchild=new NODE1(x->l,(x->l+x->r)>>1);
        x->lchild->c+=x->add*(m-(m>>1)),x->lchild->add+=x->add;
        if(!x->rchild) x->rchild=new NODE1(((x->l+x->r)>>1)+1,x->r);
        x->rchild->c+=x->add*(m>>1),x->rchild->add+=x->add;
        x->add=0;
	}
}

void Insert1(TREE1 &x,int l,int r,int L,int R){
	if(!x) x=new NODE1(L,R);
	if(x->l>=l && x->r<=r){
		x->c+=x->r-x->l+1,x->add++;
		return;
	}

	Pushdown(x,x->r-x->l+1);

	int m=(L+R)>>1;
	if(l<=m) Insert1(x->lchild,l,r,L,m);
	if(r>m) Insert1(x->rchild,l,r,m+1,R);

	Pushup(x);
}

void Insert2(TREE2 &x,int l,int r,int v){
	Insert1(x->root,l,r,1,N);
	if(x->l==x->r) return;

	int m=(x->l+x->r)>>1;
	if(v<=m) Insert2(x->lchild,l,r,v);
	else Insert2(x->rchild,l,r,v);
}

int Query1(TREE1 &x,int l,int r){
    if(!x) return 0;
    if(x->l>=l && x->r<=r) return x->c;
    Pushdown(x,x->r-x->l+1);

    int m=(x->l+x->r)>>1,ret=0;
    if(l<=m) ret+=Query1(x->lchild,l,r);
    if(r>m) ret+=Query1(x->rchild,l,r);

    return ret;
}

int Query2(TREE2 &x,int l,int r,int v){
    if(x->l==x->r) return x->l;

    int m=Query1(x->rchild->root,l,r);
    if(v<=m) return Query2(x->rchild,l,r,v);
    else return Query2(x->lchild,l,r,v-m);
}

int main(){
	cin >> N >> M;
	Build2(root,1,N);
	for(int i=1,t,a,b,c;i<=M;i++){
		cin >> t >> a >> b >> c;
		if(t==1) Insert2(root,a,b,c);
		if(t==2) cout << Query2(root,a,b,c) << endl;
	}

	return 0;
}



你可能感兴趣的:(BZOJ3110 JZOI2013 K大数查询 线段树套线段树)