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; }