有了上一题的经验(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. 2015第43周一solr相关概念

    Solr是一种开放源码的.基于Lucene的搜索服务器.它易于安装和配置,而且附带了一个基于HTTP 的管理界面.   官网:http://lucene.apache.org/solr/ solr学习 ...

  2. C# 日期格式化的中的 正斜杠的问题

    Console.WriteLine(DateTime.Now.ToString("yyyy/MM/dd" )); //这行代码, 如果你在系统日期格式默认的情况下输出 2013/0 ...

  3. POJ 1503 Integer Inquiry 简单大数相加

    Description One of the first users of BIT's new supercomputer was Chip Diller. He extended his explo ...

  4. cmd的copy命令合并多个文件

    1.1个a.jpg文件:1个b.php文件(一句话木马)

  5. c++ 流基本概念

    前言 在程序经常实现数据的输入和输出,c++通过一种称为流(stream)的机制提供了更为精良的输入和输出方法.流是一种灵活且面向对象的I/o方法. 根据操作对象不同分为文件流.字符串流.控制台流. ...

  6. 你的Jsp页面有黄×么,有黄色问号么?Multiple annotations found at this line: - Invalid location of tag (form). - No

    jsp页面有黄色问号代表我们的html标签不符合规范 对于很多人拿到页面美工给的页面,有时候很多都有黄色的问号. 为什么会这样呢? Multiple annotations found at this ...

  7. [Javascript] Using JSHint for Linting with Gulp

    gulpfile.js var gulp = require('gulp'); var jshint = require('gulp-jshint'); var stylish = require(' ...

  8. [Javascript] Array - Conact

    For example there are two array of object and you want to print out each element, it is bad if you u ...

  9. Unix网络编程代码 第13章 守护进程和inetd超级服务器

    1. 概述 守护进程是在后台运行且不与任何控制终端关联的进程.unix系统通常有很多守护进程在后台运行,执行不同的管理任务.    守护进程没有控制终端通常源于它们由系统初始化脚本启动.然而守护进程也 ...

  10. UITableView beginUpdate和endUpdate使用的前提

    转载地址:http://blog.csdn.net/vieri_ch/article/details/46893023 UITableView有两个方法,用于单元格动画变化的方法,beginUpdat ...