ZOJ - 2112

\[\
\]

(那些说这道题是树状数组套主席树的人一定对主席树有误解!)

这里我们用树状数组套线段树来解决来写

首先 , 我们需要有n棵线段树(不是\(n^2\)空间,别慌)

我们用这些线段树存储值域$ [l,r] $内数的个数

基于主席树的思想,我们的线段树是要相减的,记录的是前缀

由于要更新前缀,我们必须快速更新,所以采用树状数组来写

事实上,这里线段树的本质并非主席树,而是动态开点的线段树

(这两者是有显著差异的)

这是主席数的单点修改

struct Functional_SegmentTree{
void Add(int p,int pre,int l,int r,int x,int y){
s[p]=s[pre]+y;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) rs[p]=rs[pre],Add(ls[p]=++cnt,ls[pre],l,mid,x,y);
else ls[p]=ls[pre],Add(rs[p]=++cnt,rs[pre],mid+1,r,x,y);
}
};

是路径上的所有点都要新开节点,而实际上动点线段树不是开新点,只是当你的儿子要访问了却还未开出来时才需要开

所以代码应该是这样的

void Add(int p,int l,int r,int x,int y){
s[p]+=y;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) Add(ls[p]?ls[p]:(ls[cnt+1]=rs[cnt+1]=s[cnt+1]=0,ls[p]=++cnt),l,mid,x,y);
else Add(rs[p]?rs[p]:(ls[cnt+1]=rs[cnt+1]=s[cnt+1]=0,rs[p]=++cnt),mid+1,r,x,y);
}

(略有压行)

所以整体上应该是树状数组更新动点线段树

但是由于这题卡空间 (过于罪恶)

所以我们应该先开一个主席树存下原来的值

(为什么这样能省空间呢?因为树状数组更新的空间复杂度是\(log^2(n)\),主席树更新是log(n)的)

于是代码会长这样

const int N=50100,M=10010,K=1520110;
int n,m; int ncnt;
int a[N],b[N+M],c[M],d[M],e[M];
int cnt;
int ls[K],rs[K],s[K];
int rt[N]; struct hjt{
void Add(int p,int pre,int l,int r,int x,int y){
s[p]=s[pre]+y;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) rs[p]=rs[pre],Add(ls[p]=++cnt,ls[pre],l,mid,x,y);
else ls[p]=ls[pre],Add(rs[p]=++cnt,rs[pre],mid+1,r,x,y);
}
}H;
struct sts{
void Add(int p,int l,int r,int x,int y){
s[p]+=y;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) Add(ls[p]?ls[p]:(ls[cnt+1]=rs[cnt+1]=s[cnt+1]=0,ls[p]=++cnt),l,mid,x,y);
else Add(rs[p]?rs[p]:(ls[cnt+1]=rs[cnt+1]=s[cnt+1]=0,rs[p]=++cnt),mid+1,r,x,y);
}
int T[N];
vector <int> X,Y;
int Que(int l,int r,int k){
if(l==r) return l;
int mid=(l+r)>>1;
int t=0;
rep(i,0,X.size()-1) t+=s[ls[X[i]]];
rep(i,0,Y.size()-1) t-=s[ls[Y[i]]];
if(t>=k) {
rep(i,0,X.size()-1) X[i]=ls[X[i]];
rep(i,0,Y.size()-1) Y[i]=ls[Y[i]];
return Que(l,mid,k);
} else {
rep(i,0,X.size()-1) X[i]=rs[X[i]];
rep(i,0,Y.size()-1) Y[i]=rs[Y[i]];
return Que(mid+1,r,k-t);
}
}
int query(int l,int r,int k){
int p=r; X.clear();X.push_back(rt[r]);
while(p) X.push_back(T[p]),p-=p&-p;
p=l-1;Y.clear();Y.push_back(rt[l-1]);
while(p) Y.push_back(T[p]),p-=p&-p;
return Que(1,ncnt,k);
}
void Upd(int p,int x,int y){
while(p<=n) Add(T[p]?T[p]:(ls[cnt+1]=rs[cnt+1]=s[cnt+1]=0,T[p]=++cnt),1,ncnt,x,y),p+=p&-p;
}
}S; char opt[N][1]; int main(){
rep(kase,1,rd()){
n=rd(),m=rd();
cnt=0; memset(S.T,0,sizeof S.T);
rep(i,1,n) a[i]=b[i]=rd();
ncnt=n;
rep(i,1,m) {
scanf("%s",opt[i]);
if(opt[i][0]=='Q'){
c[i]=rd(),d[i]=rd(),e[i]=rd();
} else {
c[i]=rd(),d[i]=rd();
b[++ncnt]=d[i];
}
}
sort(b+1,b+ncnt+1);ncnt=unique(b+1,b+ncnt+1)-b-1;
rep(i,1,n) {
a[i]=lower_bound(b+1,b+ncnt+1,a[i])-b;
H.Add(rt[i]=++cnt,rt[i-1],1,ncnt,a[i],1);
}
rep(i,1,m){
if(opt[i][0]=='Q'){
int ans=S.query(c[i],d[i],e[i]);
printf("%d\n",b[ans]);
}else {
d[i]=lower_bound(b+1,b+ncnt+1,d[i])-b;
S.Upd(c[i],a[c[i]],-1);
S.Upd(c[i],a[c[i]]=d[i],1);
}
}
}
}

Dynamic_Rankings(动态区间第k大)的更多相关文章

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

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

  2. hdu5412(动态区间第k大)

    CRB and Queries Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Other ...

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

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

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

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

  5. 整体二分求动态区间第k大

    比树状数组套主席树不知道高到哪里去了,solve(l,r,L,R)就是对于L,R的操作区间的答案都在l,r区间里,然后递归下去 复杂度O(nlognlogn),每个操作会执行logn次就是o(nlog ...

  6. 动态区间第K大

    整体二分. 主要需要注意的一点是,对于每个删除操作,若删除操作被算入贡献,则最开始的插入操作也一定会被算入,所以不必担心删除删错. #include<cstdio> #include< ...

  7. 整体二分(模板二)动态区间第K大

    这才是更一般的二分写法--HDU5412 #define IOS ios_base::sync_with_stdio(0); cin.tie(0); #include <cstdio>// ...

  8. 静态区间第k大(主席树)

    POJ 2104为例(主席树入门题) 思想: 可持久化线段树,也叫作函数式线段树,也叫主席树(高大上). 可持久化数据结构(Persistent data structure):利用函数式编程的思想使 ...

  9. 【ZOJ2112】【整体二分+树状数组】带修改区间第k大

    The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with t ...

随机推荐

  1. 使用国内作者制作的gcr.io镜像安装工具

    项目地址:https://github.com/zhangguanzhang/gcr.io How to use? 拉取 假设需要拉取gcr.io/google_containers/pause:3. ...

  2. dubbo循序渐进 - Jenkins自动化部署

    最新版安装docker pull jenkinsci/jenkins sudo chown -R 1000:1000 ~/jenkins docker run -d -p : -m 1024m -v ...

  3. js中 !==和 !=的区别是什么

    1.比较结果上的区别 !=返回同类型值比较结果. !== 不同类型不比较,且无结果,同类型才比较. 2.比较过程上的区别 != 比较时,若类型不同,会偿试转换类型. !== 只有相同类型才会比较. 3 ...

  4. 英文finaunce金融

    金融 1.指货币的发行.流通和回笼,贷款的发放和收回,存款的存入和提取,汇兑的往来等经济活动. 胡适<国际的中国>:“我们更想想这几年国内的资产阶级,为了贪图高利债的利益,拚命的借债给中国 ...

  5. android studio学习----调试---断点调试

    Android Studio调试其实也非常方便,一般问题直接通过AS的DDMS的Logcat就可以搞定.AS支持类似Eclipse的DDMS的所有功能.这里要说的是疑难问题的调试方式,即断点调试. 首 ...

  6. APP开发基础知识(转载)

    来源:https://www.cnblogs.com/wangsea/p/9413672.html 本文针对小白用户对App做一个简单的介绍,首先要了解App都有哪些类型,不同的类型适用于哪些需求,用 ...

  7. RxJS——调度器(Scheduler)

    调度器 什么是调度器?调度器是当开始订阅时,控制通知推送的.它由三个部分组成. 调度是数据结构.它知道怎样在优先级或其他标准去存储和排队运行的任务 调度器是一个执行上下文.它表示任务在何时何地执行(例 ...

  8. Golang: 模拟搜索引擎爬虫

    最近网站需要针对百度做 SEO 优化,用 Go 语言写了个测试程序,模拟一下百度的爬虫,看看返回的内容是否正确. 代码很简单,就是发送一个请求,把百度相关的信息放入请求头中即可,代码如下: packa ...

  9. Hive安装部署与配置

    Hive安装部署与配置 1.1 Hive安装地址 1)Hive官网地址: http://hive.apache.org/ 2)文档查看地址: https://cwiki.apache.org/conf ...

  10. Odoo MRP模块

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10825963.html 一:MRP MRP:产品制造管理. 产品制造业务设计到以下几个关键概念: 1)BOM ...