标签:
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1602 Accepted Submission(s): 409
题目大意:给你一个数列有n个数,q次询问。询问1可以把某个位置改为值b。询问2然后问L - R之间第k大的数是多少。简单来说,就是带修改的动态区间第k大问题。
解题思路:用线段树维护Ci在去重后的所有可能出现在数列中的数当中的大小排名,用Treap维护Ci在数列中的位置关系。其实我觉得这才是内涵。然后对于查询区间L - R的第k大。那么如果在线段树左儿子代表的Treap树中在R位置之前的个数减去左儿子代表的Treap树中的(L-1)之前的个数大于k,那么就可以在左儿子中找位置。
#include<stdio.h> #include<string.h> #include<time.h> #include<algorithm> using namespace std; #define mid (L+R)/2 #define lson rt*2,L,mid #define rson rt*2+1,mid+1,R const int maxn=1e6; struct Treap{ int rk; int coun; int sz; int v; Treap *ch[2]; Treap() { coun=0; sz=0; rk=-maxn; // v=0; } int cmp(int x) const { if(x==v){ return -1; } return x<v ? 0:1; } }; Treap *seg[maxn*8]; Treap *null; int oper[maxn][4]; int a[maxn],b[maxn*3]; int discr(int l,int r,int key){ while(l<=r){ int md=(l+r)/2; if(key<b[md]){ r=md-1; }else if(key > b[md]){ l=md+1; }else{ return md; } } return -1; } void update(Treap * &o){ o->sz = o->ch[0]->sz + o->coun + o->ch[1]->sz; } void rotate(Treap * &o,int d){ Treap *k=o->ch[d^1]; o->ch[d^1]= k->ch[d]; k->ch[d]=o; update(o); update(k); o=k; } void insert_tp(Treap * &o,int x){ if(o==null){ o = new Treap(); o->ch[0]=o->ch[1]=null; o->v = x; o->coun = 1; o->rk = rand(); }else{ int d=o->cmp(x); insert_tp(o->ch[d],x); if(o->ch[d]->rk > o->rk) rotate(o,d^1); } update(o); } void insert_seg(int rt,int L,int R,int pos,int x){ insert_tp(seg[rt],x); if(L==R) return ; if(pos<=mid){ insert_seg(lson,pos,x); }else{ insert_seg(rson,pos,x); } } void free_tp(Treap *&o){ if(o->ch[0]==null&&o->ch[1]==null){ free(o); return ; } if(o->ch[0]!=null){ free_tp(o->ch[0]); } if(o->ch[1]!=null){ free_tp(o->ch[1]); } free(o); } void clean(int rt,int L,int R){ if(L==R){ free_tp(seg[rt]); return ; } clean(lson); clean(rson); free_tp(seg[rt]); } void del_tp(Treap * &o,int x){ int d=o->cmp(x); if(d==-1){ if(o->ch[0]==null&&o->ch[1]==null){ // Treap *pt=o; o = null; free(pt); } else if(o->ch[0]==null){ Treap *pt=o; o=o->ch[1]; free(pt); }else if(o->ch[1]==null){ Treap *pt=o; o= o->ch[0]; free(pt); }else{ int d2=( o->ch[0]->rk >o->ch[1]->rk ? 1:0 ); rotate(o,d2); del_tp(o->ch[d2],x); } }else{ del_tp(o->ch[d],x); } update(o); } void del_seg(int rt,int L,int R,int pos,int x){ del_tp(seg[rt],x); if(L==R) return ; if(pos<=mid){ del_seg(lson,pos,x); }else{ del_seg(rson,pos,x); } } int select(Treap *o,int x){ if(o==null){ return 0; } if(o->v > x) return select(o->ch[0],x); return o->ch[0]->sz + o->coun +select(o->ch[1],x); } int query(int rt,int L,int R,int x,int y,int k){ if(L==R) return L; int ans=select(seg[rt*2],y)-select(seg[rt*2],x); if(ans>=k) return query(lson,x,y,k); else return query(rson,x,y,k-ans); } void init(){ null =new Treap(); null->ch[0]=null->ch[1]=null; null->sz = null->coun=0; for(int i=0;i<=maxn*4-1;i++){ seg[i] = null; } } int main(){ // freopen("1007.in","r",stdin); // freopen("OUT.txt","w",stdout); int n,Q,typ,x,y,z,nn,mm; while(scanf("%d",&n)!=EOF){ init(); mm=0; for(int i=0;i<n;i++){ scanf("%d",&a[i]); b[mm++]=a[i]; } scanf("%d",&Q); for(int i=0;i<Q;i++){ scanf("%d",&typ); oper[i][0]=typ; if(typ==2){ scanf("%d%d%d",&x,&y,&z); oper[i][1]=x; oper[i][2]=y; oper[i][3]=z; }else{ scanf("%d%d",&x,&z); oper[i][1]=x; oper[i][2]=z; b[mm++]=z; } } sort(b,b+mm); nn=1; for(int i=1;i<mm;i++){ if(b[i]!=b[i-1]){ b[nn++]=b[i]; } } for(int i=0;i<n;i++){ a[i]= discr(0,nn-1,a[i])+1; insert_seg(1,1,nn,a[i],i+1); } for(int i=0;i<Q;i++){ if(oper[i][0]==1){ int kk=0; del_seg(1,1,nn,a[oper[i][1]-1],oper[i][1]); kk=discr(0,nn-1,oper[i][2]); a[oper[i][1]-1]=kk+1; insert_seg(1,1,nn,a[oper[i][1]-1],oper[i][1]); }else{ int tmp=query(1,1,nn,oper[i][1]-1,oper[i][2],oper[i][3])-1; printf("%d\n",b[tmp]); } } clean(1,1,nn); } return 0; } /* 5 1 1 1 1 1 10 1 2 3 2 1 4 3 1 5 6 1 4 2 1 5 3 2 1 3 3 2 1 4 4 2 2 5 2 2 2 5 3 2 2 5 4 */
HDU 5412——CRB and Queries——————【线段树套Treap(并没有AC)】
标签:
原文地址:http://www.cnblogs.com/chengsheng/p/4801690.html