●ZOJ 2112 Dynamic Rankings
●赘述题目
对于一个长为n(n<50000)的序列(序列中的数小于1000000000),现有如下两种指令:
Q a b c:询问区间[a,b]中第c小的数。
C p b:将序列中的从左往右数第p个数改成b。
●题解
(整体二分应该可以做吧。。。但写不来了)
主席树+树状数组套线段树维护。
本题和POJ 2104 K-th Number相比,多了一个修改操作,但真的做得我心累。
看看POJ 2104 的查询函数:

查询区间到底是往左还是往右,这决于tmp与k大小关系。但本题因为有修改操作,导致上图的sum[ ]存的信息不正确,无法正确二分下去。所以我们需要就修改操作进行信息的更新。
对于一个修改操作C p b,我们可以发现,这个操作会影响tr[p-n]这一堆主席树,那当然是不能直接枚举这一堆主席树,挨个进行修改,显然会超时。
于是便尝试再另外弄一个东西来单独维护修改后的信息。
不难发现,这一堆主席树,它们的修改操作是一模一样的,那便可以看作是一个区间修改,单点查询(如下图)呢,那我们就用树状数组来维护。

squery(x)是对树状数组的询问,表示序列区间[1-x]内有多少在[l-r](权值)范围内的数发生了变化(少了则减,多了则加)。
举个例子,当原序列为 1 2 3 4 ,已经执行了修改操作C 2 5
若 l=1,r=4:squery(1)=0; squery(2)=-1; squery(3)=-1; squery(4)=-1;
若 l=5,r=8 : squery(1)=0; squery(2)=1; squery(3)=1; squery(4)=1;
若 l=1,r=8 : squery(1)=0; squery(2)=0; squery(3)=0; squery(4)=0;
(一定要弄懂哦。)
另外,树状数组该如何维护在[l-r]范围内的数发生的变化呢,那就树套树呗(以前从未写过树套树。。。),对于每个树状数组的节点建一颗权值线段树。
○至此,便有了一个大致的修改操作的思路:
对于C p b ,
先是枚举树状数组的节点(数组数组区间修改(单点查询),不用多说了吧)
for(int i=p;i<=n;i+=lowbit(i)) xmodify( ) ,对枚举到的节点里套的权值线段树进行单点修改。
到时候查询树状数组的时候,就for(int i=p;i>0;i-=lowbit(i)) ret+=xquery( ),对每个枚举到的节点里套的权值线段树进行权值区间查询并累加就好了。
(注意:若每个树状数组节点里都套的是一棵完整的权值线段树,空间必然不够,但因为修改数不超过10000,每次修改都只修改log n条链,这意味着我们需要用到的权值线段树的某些位置,在修改时临时建就好了,最后每个树状数组节点里都套的都是我们想象的完整的权值线段树,实际上只是几条链,甚至一条链没有。)
那么,完了吗?
我们算一算: m个操作,每个操作有一个log级别的主席树查询,再有一个 log级别的树状数组查询, 再套一个log级别的权值线段树查询,总的是复杂度是mlogloglog,可能要超时呢。
看看别的大佬的做法,每次主席树查询到[l-r]区间时,我们查询的每个权值线段树区间也是[l-r](且该区间是直接二分得到的,而不是几个小区间拼凑而来),那便可以先用一个数组存下要用的权值线段树的节点,当询问树状数组时由储存的权值线段树的节点直接获取权值区间信息便是了。这样是一个 mloglog的复杂度。
所以,这里生长着两棵树,一颗是主席树(保存初始信息),一颗是套了线段树的树状数组(维护修改信息)。那么,本题也就结束了。
好吧,其实还有漫长的调试查错呢!
●代码
先大致解释一下函数名:(XX表示原函数名,如build,modify,squery。。。)
zXX表示关于主席树的函数;
sXX表示关于树状数组的函数;
xXX表示关于线段树的函数;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int MAXN = 60010;
const int M = 2500010;
using namespace std;
int sum[M],ls[M],rs[M];
int xx[MAXN],aa[MAXN],tr[MAXN],s[MAXN],use[MAXN];
int tot=0,cnt,n,m,pa,pb;
struct operation{
char ch;int a,b,c;
}op[10005];
int discrete(int x){return lower_bound(xx+1,xx+cnt+1,x)-xx;}
void xmodify(int &u,int l,int r,int x,int d)
{
if(!u) u=++tot,sum[u]=0;
sum[u]+=d;
if(l==r){return;}
int mid=(l+r)>>1;
if(x<=mid) xmodify(ls[u],l,mid,x,d);
else xmodify(rs[u],mid+1,r,x,d);
}
int lowbit(int x) {return x&-x;}
void smodify(int p,int x,int d)
{
for(int i=p;i<=n;i+=lowbit(i)) xmodify(s[i],1,cnt,x,d);
}
int squery(int x)
{
int ret=0;
for(int i=x;i>0;i-=lowbit(i)) ret+=sum[ls[use[i]]];
return ret;
}
void zbuild(int &u,int l,int r)
{
u=++tot; sum[u]=0;
if(l==r) return;
int mid=(l+r)>>1;
zbuild(ls[u],l,mid);
zbuild(rs[u],mid+1,r);
}
void zupdate(int &u,int last,int l,int r,int p)
{
u=++tot; sum[u]=sum[last]+1;
if(l==r) return;
ls[u]=ls[last]; rs[u]=rs[last];
int mid=(l+r)>>1;
if(p<=mid) zupdate(ls[u],ls[last],l,mid,p);
else zupdate(rs[u],rs[last],mid+1,r,p);
}
int zquery(int a,int b,int l,int r,int k)
{
if(l==r) return l;
int mid=(l+r)>>1;
int tmp=squery(pb)-squery(pa)+sum[ls[b]]-sum[ls[a]];
if(tmp>=k)
{
for(int i=pa;i>0;i-=lowbit(i)) use[i]=ls[use[i]];
for(int i=pb;i>0;i-=lowbit(i)) use[i]=ls[use[i]];
return zquery(ls[a],ls[b],l,mid,k);
}
else
{
for(int i=pa;i>0;i-=lowbit(i)) use[i]=rs[use[i]];
for(int i=pb;i>0;i-=lowbit(i)) use[i]=rs[use[i]];
return zquery(rs[a],rs[b],mid+1,r,k-tmp);
}
}
int main()
{
int ans,dd,T;
scanf("%d",&T);
while(T--)
{
tot=cnt=dd=0;
scanf("%d%d",&n,&m);
memset(s,0,sizeof(s));
memset(ls,0,sizeof(ls));
memset(rs,0,sizeof(rs));
for(int i=1;i<=n;i++) scanf("%d",&aa[i]),xx[++dd]=aa[i];
for(int i=1;i<=m;i++)
{
scanf(" %c",&op[i].ch);
if(op[i].ch=='Q') scanf("%d%d%d",&op[i].a,&op[i].b,&op[i].c);
else scanf("%d%d",&op[i].a,&op[i].b),xx[++dd]=op[i].b;
}
sort(xx+1,xx+dd+1);
cnt=unique(xx+1,xx+dd+1)-xx-1;
zbuild(tr[0],1,cnt);
for(int i=1;i<=n;i++)
{
int p=discrete(aa[i]);
zupdate(tr[i],tr[i-1],1,cnt,p);
}
for(int i=1,a,b,k;i<=m;i++)
{
a=op[i].a; b=op[i].b;
if(op[i].ch=='Q')
{
k=op[i].c;
pa=a-1; pb=b;
for(int j=pa;j>0;j-=lowbit(j)) use[j]=s[j];
for(int j=pb;j>0;j-=lowbit(j)) use[j]=s[j];
ans=zquery(tr[a-1],tr[b],1,cnt,k);
printf("%d\n",xx[ans]);
}
else
{
int x=discrete(aa[a]),y=discrete(b);
smodify(a,x,-1); smodify(a,y,1);
aa[a]=b;
}
}
}
return 0;
}
●ZOJ 2112 Dynamic Rankings的更多相关文章
- ZOJ 2112 Dynamic Rankings(动态区间第 k 大+块状链表)
题目大意 给定一个数列,编号从 1 到 n,现在有 m 个操作,操作分两类: 1. 修改数列中某个位置的数的值为 val 2. 询问 [L, R] 这个区间中第 k 大的是多少 n<=50,00 ...
- 主席树[可持久化线段树](hdu 2665 Kth number、SP 10628 Count on a tree、ZOJ 2112 Dynamic Rankings、codeforces 813E Army Creation、codeforces960F:Pathwalks )
在今天三黑(恶意评分刷上去的那种)两紫的智推中,突然出现了P3834 [模板]可持久化线段树 1(主席树)就突然有了不详的预感2333 果然...然后我gg了!被大佬虐了! hdu 2665 Kth ...
- 整体二分(SP3946 K-th Number ZOJ 2112 Dynamic Rankings)
SP3946 K-th Number (/2和>>1不一样!!) #include <algorithm> #include <bitset> #include & ...
- 整体二分&cdq分治 ZOJ 2112 Dynamic Rankings
题目:单点更新查询区间第k大 按照主席树的思想,要主席树套树状数组.即按照每个节点建立主席树,然后利用树状数组的方法来更新维护前缀和.然而,这样的做法在实际中并不能AC,原因即卡空间. 因此我们采用一 ...
- ZOJ 2112 Dynamic Rankings(主席树の动态kth)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 The Company Dynamic Rankings ...
- ZOJ 2112 Dynamic Rankings(带修改的区间第K大,分块+二分搜索+二分答案)
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
- ZOJ -2112 Dynamic Rankings 主席树 待修改的区间第K大
Dynamic Rankings 带修改的区间第K大其实就是先和静态区间第K大的操作一样.先建立一颗主席树, 然后再在树状数组的每一个节点开线段树(其实也是主席树,共用节点), 每次修改的时候都按照树 ...
- zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap
Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/show ...
- 高级数据结构(树状数组套主席树):ZOJ 2112 Dynamic Rankings
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
- ZOJ 2112 Dynamic Rankings (动态第 K 大)(树状数组套主席树)
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
随机推荐
- Java作业-网络编程
Java网络编程 关于结合以前的大作业(即我的图书馆管理系统) 我感觉,图书馆管理系统更像是一个偏向于B/S模式的体系,如果想让他可用性变得更好,可以优化的地方只有使用数据库来代替文件,我个人是没有想 ...
- 201621123057 《Java程序设计》第8周学习总结
1. 本周学习总结 思维导图归纳总结集合相关内容. 2. 书面作业 1. ArrayList代码分析 1.1 解释ArrayList的contains源代码 ArrayList是允许重复的,但当用它来 ...
- 第十一条:谨慎的覆盖clone()方法
一个类要想实现克隆,需要实现Cloneable接口,表明这个类的对象具有克隆的功能. Cloneable接口是一个mixin接口,它里面并没有任何的抽象方法,类似的接口有Serializable接口, ...
- Scrum 冲刺 第六日
Scrum 冲刺 第六日 目录 要求 项目链接 燃尽图 问题 今日任务 明日计划 成员贡献量 要求 各个成员今日完成的任务(如果完成的任务为开发或测试任务,需给出对应的Github代码签入记录截图:如 ...
- 【iOS】swift-ObjectC 在iOS 8中使用UIAlertController
iOS 8的新特性之一就是让接口更有适应性.更灵活,因此许多视图控制器的实现方式发生了巨大的变化.全新的UIPresentationController在实现视图控制器间的过渡动画效果和自适应设备尺寸 ...
- 为微软samples-for-ai贡献代码是种怎么样的体验?
推送原文链接:传送门 关注SomedayWill,了解为微软项目贡献代码的始终. 还记得微软神器samples-for-ai吗?它可不仅仅可以用来安装框架,它其实是个开源的AI样例库,以Visual ...
- JavaScript 实现二叉树
JavaScript 实现二叉树: // JavaScript 实现二叉树 function BinaryTree () { var Node = function (key) { this.key ...
- 阿里云API网关(16)客户端请求的https支持
网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...
- css(1-1)样式表
CSS Id 和 Class id 和 class 选择器 如果你要在HTML元素中设置CSS样式,你需要在元素中设置"id" 和 "class"选择器. id ...
- android- 远程调试
最近由于要在另外一台android设备上调试代码,在本机PC上查看其log.两台机器离的比较远, 无法用usb直接连接,于是在网上找了很多资料,最找使用adb connect方法解决了该问题.解决过程 ...