首页 > 代码库 > BZOJ3110 ZJOI2013 K大数查询 线段树套线段树

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

题意:给定一个数列,维护:1、在a和b之间插入c  2、询问[a,b]中的第c大

题解:

权值线段树套区间线段树

外层的权值线段树中每个节点如果维护[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;}
View Code

 

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