BZOJ 1901 Zju2112 Dynamic Rankings 题解

题意:带修改不带插入的区间k大。

裸的可持久化线段树。。由于有修改,要用树状数组维护。其它跟不带修改的可持久化线段树一样。

因为我没有找到网上用指针写的代码。。CLJ写这道题也用的不是可持久化线段树,于是我就没有任何模板可以参照。。就参考网上数组版的自己脑补了一个指针版。。你们就可以看到代码优美度下降了好多。

由于数字范围很大,我们需要把所有输入读进来然后离散化。。不离散化的话就要动态开点(这个我暂时还不会)

这份代码用的空间比较多。。在zju是A不了的,需要空间优化(怎么优化我也不知道)

  1 #include<cstdio>
  2 #include<algorithm>
  3 const int MAXN=10000+5;
  4 const int INF=~0U>>1;
  5 const int BUFFER_SIZE=10000;
  6 const int MAXM=10000+5;
  7 struct Tree{
  8     Tree* pl,*pr;
  9     int l,r,sum;
 10     Tree* set(int _l,int _r,Tree* _pl,Tree* _pr)
 11     {
 12         l=_l;r=_r;pl=_pl;pr=_pr;
 13         sum=pl->sum+pr->sum;
 14         return this;
 15     }
 16     Tree* set(int _l,int _r,int all);
 17     Tree* add(int pos,int ad);
 18 };
 19 Tree* buffer=0,*cur;
 20 inline Tree* get()
 21 {
 22     if(!buffer || cur-buffer==BUFFER_SIZE)
 23         buffer=new Tree[BUFFER_SIZE],cur=buffer;
 24     return cur++;
 25 }
 26 Tree* Tree::set(int _l,int _r,int all)
 27 {
 28     l=_l;r=_r;
 29     if(l+1==r) sum=all;
 30     else
 31     {
 32         int m=(l+r)>>1;
 33         pl=get()->set(l,m,all);
 34         pr=get()->set(m,r,all);
 35         sum=pl->sum+pr->sum;
 36     }
 37     return this;
 38 }
 39 Tree* Tree::add(int pos,int ad)
 40 {
 41     if(l+1==r) return get()->set(l,r,sum+ad);
 42     int m=(l+r)>>1;
 43     if(pos<m) return get()->set(l,r,pl->add(pos,ad),pr);
 44     else return get()->set(l,r,pl,pr->add(pos,ad));
 45 }
 46 inline int lowbit(int x)
 47 {    return x&-x;    }
 48 int n,m;
 49 Tree* root[MAXN];
 50 void update(int x,int pos,int ad)
 51 {
 52     for(;x<=n;x+=lowbit(x))
 53         root[x]=root[x]->add(pos,ad);
 54 }
 55 Tree* ptl[MAXN],*ptr[MAXN];
 56 int lnum,rnum;
 57 inline void get_trees(int x,int y)
 58 {
 59     lnum=rnum=0;
 60     for(;x>0;x-=lowbit(x))
 61         ptl[lnum++]=root[x];
 62     for(;y>0;y-=lowbit(y))
 63         ptr[rnum++]=root[y];
 64 }
 65 inline int get_sum()
 66 {
 67     int cnt1=0,cnt2=0;
 68     for(int i=0;i<lnum;++i) cnt1+=ptl[i]->pl->sum;
 69     for(int i=0;i<rnum;++i) cnt2+=ptr[i]->pl->sum;
 70     return cnt2-cnt1;
 71 }
 72 inline int query(int x,int y,int k)
 73 {
 74     get_trees(x-1,y);
 75     while(ptr[0]->l +1 < ptr[0]->r)
 76     {
 77         int cnt=get_sum();
 78         if(cnt<=k)
 79         {
 80             k-=cnt;
 81             for(int i=0;i<lnum;++i) ptl[i]=ptl[i]->pr;
 82             for(int i=0;i<rnum;++i) ptr[i]=ptr[i]->pr;
 83         }
 84         else
 85         {
 86             for(int i=0;i<lnum;++i) ptl[i]=ptl[i]->pl;
 87             for(int i=0;i<rnum;++i) ptr[i]=ptr[i]->pl;
 88         }
 89     }
 90     return ptr[0]->l;
 91 }
 92 struct Ask{
 93     int kind,a,b,c;
 94 }ask[MAXM];
 95 int w[MAXN],sortw[MAXN+MAXM];
 96 int main()
 97 {
 98     freopen("1.in","r",stdin);
 99     scanf("%d%d",&n,&m);
100     int p;
101     for(int i=0;i<n;++i)
102         scanf("%d",w+i),sortw[i]=w[i];
103     p=n;
104     char cmd[5];
105     for(int i=0;i<m;++i)
106     {
107         scanf("%s",cmd);
108         if(cmd[0]==‘Q‘)
109         {
110             ask[i].kind=0;
111             scanf("%d%d%d",&ask[i].a,&ask[i].b,&ask[i].c);
112         }
113         else
114         {
115             ask[i].kind=1;
116             scanf("%d%d",&ask[i].a,&ask[i].b);
117             sortw[p]=ask[i].b;
118             p++;
119         }
120     }
121     std::sort(sortw,sortw+p);
122     int nn=std::unique(sortw,sortw+p)-sortw;
123     for(int i=0;i<n;++i) w[i]=std::lower_bound(sortw,sortw+nn,w[i])-sortw;
124     root[0]=get()->set(0,nn,0);
125     for(int i=1;i<=n;++i) root[i]=root[0]->add(w[i-1],1);
126     for(int i=1;i<=n;++i) update(i+lowbit(i),w[i-1],1);
127     for(int i=0;i<m;++i)
128     {
129         if(!ask[i].kind) printf("%d\n",sortw[query(ask[i].a,ask[i].b,ask[i].c-1)]);
130         else
131         {
132             int t=std::lower_bound(sortw,sortw+nn,ask[i].b)-sortw;
133             update(ask[i].a,w[ask[i].a-1],-1);
134             w[ask[i].a-1]=t;
135             update(ask[i].a,t,1);
136         }
137     }
138     return 0;
139 }

时间: 2024-08-02 14:17:49

BZOJ 1901 Zju2112 Dynamic Rankings 题解的相关文章

BZOJ 1901: Zju2112 Dynamic Rankings 区间k大 带修改 在线 线段树套平衡树

之前写线段树套splay数组版..写了6.2k..然后弃疗了.现在发现还是很水的..嘎嘎.. zju过不了,超时. upd:才发现zju是多组数据..TLE一版才发现.然后改了,MLE...手写内存池..尼玛终于过了..附zju2112代码于后. bzoj倒是过了,1A的感觉还是很爽的..可是时间不好看..这就是所谓\(O(nlog^3n)\)的复杂度的可怜之处么? 写挂的地方: insert一定要是传地址指针进去. delete时先把地址指针delete掉,最后把是地址指针指向左儿子or右儿子

bzoj 1901: Zju2112 Dynamic Rankings(树套树)

1901: Zju2112 Dynamic Rankings 经典的带修改求区间第k小值问题 树套树模板,我是用的线段树套splay实现的,而且用的数组模拟的,所以可能空间略大,bzoj过了,zoj过不了. 思路很简单,用线段树维护区间,用splay维护区间内的权值,然后询问的时候,二分答案key,然后在区间内找小于key的数有多少个. 贴上模板: #include<stdio.h> #include<string.h> #include<algorithm> #def

Bzoj 1901: Zju2112 Dynamic Rankings 树套树,线段树,平衡树,Treap

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6471  Solved: 2697[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i

BZOJ 1901: Zju2112 Dynamic Rankings( 树状数组套主席树 )

裸的带修改主席树.. 之前用BIT套Splay( http://www.cnblogs.com/JSZX11556/p/4625552.html )A过..但是还是线段树好写...而且快(常数比平衡树小). 时空复杂度是O(Nlog(N)+Mlog^2(N)) ------------------------------------------------------------------------- #include<cstdio> #include<cstring> #in

bzoj 1901: Zju2112 Dynamic Rankings -- 主席树,树状数组,哈希

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1 ],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改 变后的a继续回答上面的问题. Input 第一行有两个正整数n(1≤

bzoj 1901: Zju2112 Dynamic Rankings

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6245  Solved: 2593[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题.你需

1901: Zju2112 Dynamic Rankings

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5268  Solved: 2207[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i

BZOJ1901:Zju2112 Dynamic Rankings——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=1901 Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1 ],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改 变后的a继续回答上面的问题. Input 第一行有两个正整数n(1≤n≤10000),m(1≤m≤1000

【BZOJ 1901】Dynamic Rankings

Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题.你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令.对于每一个询问指令,你必须输出正确的回答. (带修改的区间第K小) Input 第一行有两个正