有了上一题的经验(POJ的静态区间第K最值)再解决这道题就轻松多了

空间5256KB,时间3330ms,如果把动态开点的平衡树换成数组模拟的话应该会更快

之所以选择了平方分割而不是树套树,不仅是所谓趁热打铁,更是因为:

平方分割的修改操作,无论编程复杂度还是时间复杂度都远优于树套树。

代码如下:(鄙人不才,不会压代码,所以写了300多行Σ( ° △ °|||)

 template <class T>
 struct SbtNode
 {
     typedef SbtNode<T> Node;
     Node* lch;
     Node* rch;

     T val;
     int lSize;
     int rSize;

     SbtNode(const T& _val):
             lch(),rch(),val(_val),lSize(),rSize() {}
     void assign(const T& _val)
     {
         lch=rch=;
         val=_val;
         lSize=rSize=;
     }
 };

 template <class T,class Comp>
 struct SizeBlcTree
 {
     ,Left=,Right= };
     typedef SbtNode<T> Node;
     typedef SizeBlcTree<T,Comp> Sbt;

     Node* root;
     Comp cmp;

     SizeBlcTree():root() {}
     ~SizeBlcTree() { clear(); }

     void clear_aux(Node* _cur)
     {
         if(_cur->lch) clear_aux(_cur->lch);
         if(_cur->rch) clear_aux(_cur->rch);
         delete _cur;
     }

     void clear()
     {
         if(root) clear_aux(root);
         root=;
     }

     Node* lRotate(Node* _cur)
     {
         Node* next=_cur->rch;
         _cur->rch=next->lch;
         next->lch=_cur;

         _cur->rSize=next->lSize;
         next->lSize+=(_cur->lSize+);

         return next;
     }

     Node* rRotate(Node* _cur)
     {
         Node* next=_cur->lch;
         _cur->lch=next->rch;
         next->rch=_cur;

         _cur->lSize=next->rSize;
         next->rSize+=(_cur->rSize+);

         return next;
     }

     Node* insert_aux(const T& _val,Node* _cur)
     {
         if(!_cur) return new Node(_val);

         if(cmp(_val,_cur->val))
         {
             ++_cur->lSize;
             _cur->lch=insert_aux(_val,_cur->lch);
             if(_cur->lch->lSize > _cur->rSize) return rRotate(_cur);
             else if(_cur->lch->rSize > _cur->rSize)
             {
                 _cur->lch=lRotate(_cur->lch);
                 return rRotate(_cur);
             }
             else return _cur;
         }
         else
         {
             ++_cur->rSize;
             _cur->rch=insert_aux(_val,_cur->rch);
             if(_cur->rch->rSize > _cur->lSize) return lRotate(_cur);
             else if(_cur->rch->lSize > _cur->lSize)
             {
                 _cur->rch=rRotate(_cur->rch);
                 return lRotate(_cur);
             }
             else return _cur;
         }
     }

     Sbt& operator << (const T& _val)
     {
         root=insert_aux(_val,root);
         return *this;
     }

     Node* erase_aux(const T& _val,Node* _cur,bool& _found)
     {
         if(!_cur)
         {
             _found=false;
             ;
         }
         if(cmp(_val,_cur->val))
         {
             _cur->lch=erase_aux(_val,_cur->lch,_found);
             if(_found) --_cur->lSize;
             return _cur;
         }
         if(cmp(_cur->val,_val))
         {
             _cur->rch=erase_aux(_val,_cur->rch,_found);
             if(_found) --_cur->rSize;
             return _cur;
         }

         _found=true;
         ;
         ;
         ;
         Node* res;
         Node* &prev=res;

         switch(status)
         {
         :
             delete _cur;
             ;
         :
             res=_cur->lch;
             delete _cur;
             return res;
         :
             res=_cur->rch;
             delete _cur;
             return res;
         :
             prev=_cur;
             if(prev->rch->lch)
             {
                 --prev->rSize;
                 prev=prev->rch;

                 while(prev->lch->lch)
                 {
                     --prev->lSize;
                     prev=prev->lch;
                 }
                 _cur->val=prev->lch->val;
                 prev->lch=erase_aux(prev->lch->val,prev->lch,_found);
                 --prev->lSize;
             }
             else
             {
                 _cur->val=_cur->rch->val;
                 _cur->rch=erase_aux(_cur->rch->val,_cur->rch,_found);
                 --_cur->rSize;
             }
             return _cur;
         }
     }

     Sbt& operator >> (const T& _val)
     {
         bool found=false;
         root=erase_aux(_val,root,found);
         return *this;
     }

     int notMoreCount(const T& _val)
     {
         Node* cur=root;
         ;
         while(cur)
         {
             if(cmp(_val,cur->val)) cur=cur->lch;
             else
             {
                 res+=(cur->lSize+);
                 cur=cur->rch;
             }
         }
         return res;
     }

     int lessCount(const T& _val)
     {
         Node* cur=root;
         ;
         while(cur)
         {
             if(cmp(cur->val,_val))
             {
                 res+=(cur->lSize+);
                 cur=cur->rch;
             }
             else cur=cur->lch;
         }
         return res;
     }
 };

 ;
 ;
 ;
 ;

 #include <functional>
 #include <algorithm>

 int unOrd[bktCount*bktSize];

 using std::less;
 SizeBlcTree<int,less<int> > all;
 SizeBlcTree<int,less<int> > bucket[bktCount];
 int N,K;
 int cs;

 #include <cstdio>

 void init()
 {
     scanf("%d%d",&N,&K);
     ;i<N;i++)
     {
         scanf("%d",unOrd+i);
         all<<unOrd[i];
         bucket[i>>bktDigit] << unOrd[i];
     }
 }

 inline void enumerate(int _rL,int _rR,int _val,int& _less,int& _notMore)
 {
     for(int i=_rL;i<=_rR;i++) if(unOrd[i]<=_val)
     {
         _notMore++;
         if(unOrd[i]<_val) _less++;
     }
 }

 int getAns(int _rL,int _rR,int _k)
 {
     int bktL = _rL>>bktDigit;
     int bktR = _rR>>bktDigit;

     int prevVal;
     SbtNode<int> *cur=all.root;
     while(cur)
     {
         ;
         ;
         if(bktL==bktR) enumerate(_rL,_rR,cur->val,less,notMore);
         else
         {
             ;i<bktR;i++)
             {
                 notMore += bucket[i].notMoreCount(cur->val);
                 less += bucket[i].lessCount(cur->val);
             }
             enumerate(_rL,((bktL+)<<bktDigit)-,cur->val,less,notMore);
             enumerate(bktR<<bktDigit,_rR,cur->val,less,notMore);
         }
         if(less<_k && notMore>=_k) return cur->val;
         prevVal=cur->val;
         if(less>=_k) cur=cur->lch;
         else cur=cur->rch;
     }
     return prevVal;
 }

 void solve()
 {
     char cmd;
     do cmd=getchar(); while(cmd==' ' || cmd=='\n');
     if(cmd=='Q')
     {
         int rL,rR,k;
         scanf("%d%d%d",&rL,&rR,&k);
         printf(,rR-,k));
     }
     else
     {
         int pos,v;
         scanf("%d%d",&pos,&v);
         --pos;
         all<<v;
         bucket[pos>>bktDigit] >> unOrd[pos];
         bucket[pos>>bktDigit] << (unOrd[pos]=v) ;
     }
 }

 void reset()
 {
     all.clear();
     int used=N>>bktDigit;
     ;i<=used;i++) bucket[i].clear();
 }

 int main()
 {
     scanf("%d",&cs);
     while(cs--)
     {
         init();
         while(K--) solve();
         reset();
     }
     ;
 }

简析:

可以和我的这篇随笔进行对比:http://www.cnblogs.com/Onlynagesha/p/5353531.html

前面将近2/3都是SBT的模板

平方分割的大致思路和静态第k大是一样的,中间分块高效维护,然后枚举两边的零头

但在动态第k大问题中,每个桶维护的都是一棵平衡树。这样我们便可以高效的修改。

若要进行高效的二分,我们还要维护一颗“总的”平衡树all,存放当前所有的数值。

二分的时候从all的根节点开始,边界是走到叶子节点。二分的每一步都有三种可能:

(1)当前节点就是答案

(2)当前节点的值过大,那么取下一个值为其左孩子

(3)当前节点的值过大,那么取下一个值为其右孩子

注意体会基于树的二分和基于区间的二分的差异。前者难以保证“可能”会成为答案的值被保留(因为每走一步当前的值就被“丢弃”了),而后者可以

另外维护all的时候还有一个小技巧:修改数值时只需将新值插入而不需将旧值删去,这样可以省下一点时间常数

被“删去”的值在之后的二分过程中一定不会满足第(1)种可能

ZOJ2112 Dynamic Rankings 动态区间第K最值 平方分割的更多相关文章

  1. POJ2104 K-th Number 静态区间第k最值 平方分割

    干掉这道题的那一刻,我只想说:我终于**的AC了!!! 最终内存1344K,耗时10282ms,比起归并树.划分树以及其他各种黑科技,这个成绩并不算光彩⊙﹏⊙ 但至少,从最初的无数次TLE到最终的AC ...

  2. ZOJ2112--Dynamic Rankings (动态区间第k大)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  3. 【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树状数组套主席树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1901 首先还是吐槽时间,我在zoj交无限tle啊!!!!!!!!我一直以为是程序错了啊啊啊啊啊啊. ...

  4. 【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树套树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1901 这题调了我相当长的时间,1wa1a,我是第一次写树套树,这个是树状数组套splay,在每个区间 ...

  5. Dynamic Rankings || 动态/静态区间第k小(主席树)

    JYF大佬说,一星期要写很多篇博客才会有人看 但是我做题没有那么快啊QwQ Part1 写在前面 区间第K小问题一直是主席树经典题=w=今天的重点是动态区间第K小问题.静态问题要求查询一个区间内的第k ...

  6. ZOJ 1112 Dynamic Rankings【动态区间第K大,整体二分】

    题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112 题意: 求动态区间第K大. 分析: 把修改操作看成删除与增加 ...

  7. bzoj1901&zoj2112&cogs257 Dynamic Rankings(动态排名系统)

    bzoj1901&zoj2112&cogs257 Dynamic Rankings(动态排名系统) cogs zoj bzoj-权限 题解 bzoj和zoj都是骗访问量的233,我没有 ...

  8. 主席树--动态区间第k小

    主席树--动态区间第\(k\)小 模板题在这里洛谷2617. 先对几个问题做一个总结: 阅读本文需要有主席树的基础,也就是通过区间kth的模板题. 静态整体kth: sort一下找第k小,时间复杂度\ ...

  9. ZOJ 2112 Dynamic Rankings(动态区间第 k 大+块状链表)

    题目大意 给定一个数列,编号从 1 到 n,现在有 m 个操作,操作分两类: 1. 修改数列中某个位置的数的值为 val 2. 询问 [L, R] 这个区间中第 k 大的是多少 n<=50,00 ...

随机推荐

  1. 【转】MFC获取程序目录路径方法

    原文网址:http://yeahyuanqing.blog.163.com/blog/static/118025091201149480818/ MFC获得当前应用程序目录的GetCurrentDir ...

  2. MySQL中的类Decode用法

    SELECT DISTINCT ( CASE ' THEN '关羽' ' THEN ' 张飞' ' THEN ' 赵云' ' THEN ' 马超' ' THEN ' 黄忠' ' THEN ' 魏延' ...

  3. StoryBoard 的使用

    简单入门: http://my.oschina.net/plumsoft/blog/53886 详细操作:http://www.cnblogs.com/buro79xxd/archive/2012/0 ...

  4. JavaScript高级程序设计10.pdf

    String类型有几种操作字符串的方法 concat()方法拼接任意多个字符串,不修改原字符串 var stringValue=“hello ”; var result=stringValue.con ...

  5. 关于ATL的rgs注册文件

    转自:http://blog.csdn.net/idiszerg/article/details/3875934 使用ATL向导的话,会在resource中产生一个rgs的注册脚本文件放在" ...

  6. verilog 双向IO实现

    网上搜索了一番,示例挺多,但发现都写的是 input in; output out; 然后  assign io= (oe)?out:1'bz;就有点想不明白了,当IO方向为输出时,应该输出out的值 ...

  7. dp poj 1080 Human Gene Functions

    题目链接: http://poj.org/problem?id=1080 题目大意: 给两个由A.C.T.G四个字符组成的字符串,可以在两串中加入-,使得两串长度相等. 每两个字符匹配时都有个值,求怎 ...

  8. 应用360云盘与SVN版本管理服务器搭建基于云端的版本控制软件

    步骤一:(安装软件) 1.TortoiseSVN 2.VisualSVN-Server-2.71 3.安装云盘客户端360wangpan_setup 步骤二:(VisualSVN Server设置) ...

  9. java实现url转码、解码

    URL由来: 一般来说,URL只能使用英文字母.阿拉伯数字和某些标点符号,不能使用其他文字和符号.比如,世界上有英文字母的网址 “http://www.abc.com”,但是没有希腊字母的网址“htt ...

  10. 【Android - 框架】之Glide的使用

    一.Glide简介: Glide是Google官方推荐的一个图片加载和缓存的开源库,它不仅能实现平滑的图片列表滚动效果,还支持远程图片的获取.大小调整和展示,并且可以加载GIF图片.Glide相比与U ...