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

 

posted @ 2017-02-26 14:02  WDZRMPCBIT  阅读(119)  评论(0编辑  收藏  举报