●赘述题目

对于一个长为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的更多相关文章

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

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

  2. 主席树[可持久化线段树](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 ...

  3. 整体二分(SP3946 K-th Number ZOJ 2112 Dynamic Rankings)

    SP3946 K-th Number (/2和>>1不一样!!) #include <algorithm> #include <bitset> #include & ...

  4. 整体二分&cdq分治 ZOJ 2112 Dynamic Rankings

    题目:单点更新查询区间第k大 按照主席树的思想,要主席树套树状数组.即按照每个节点建立主席树,然后利用树状数组的方法来更新维护前缀和.然而,这样的做法在实际中并不能AC,原因即卡空间. 因此我们采用一 ...

  5. ZOJ 2112 Dynamic Rankings(主席树の动态kth)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 The Company Dynamic Rankings ...

  6. ZOJ 2112 Dynamic Rankings(带修改的区间第K大,分块+二分搜索+二分答案)

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

  7. ZOJ -2112 Dynamic Rankings 主席树 待修改的区间第K大

    Dynamic Rankings 带修改的区间第K大其实就是先和静态区间第K大的操作一样.先建立一颗主席树, 然后再在树状数组的每一个节点开线段树(其实也是主席树,共用节点), 每次修改的时候都按照树 ...

  8. zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap

    Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/show ...

  9. 高级数据结构(树状数组套主席树):ZOJ 2112 Dynamic Rankings

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

  10. ZOJ 2112 Dynamic Rankings (动态第 K 大)(树状数组套主席树)

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

随机推荐

  1. org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be res

    解决:web项目出现如上问题,据查是版本问题: JSTL 1.0 的声明是: <%@ taglib prefix="c" uri="http://java.sun. ...

  2. DistBlockNet:A Distributed Blockchains-Based Secure SDN Architecture for IOT Network

    现有问题 随着IOT中智能设备多样性和数目的增加,IOT的灵活性,效率,可用性,安全性和可扩展性的问题越来越明显. 实验目标 按照高适应性,可用性,容错性,性能,可靠性,可扩展性和安全性的设计原则,构 ...

  3. 过滤器Filter与监听器Listener

    过滤器Filter 过滤器也是一种servlet   它也可以对用户的请求进行处理  , 但是他所做的处理,只是一些轻量级的处理.Fileter就好像jsp页面与servlet之间的一道关卡,如果这个 ...

  4. JVM笔记7-内存分配与回收策略

    1.对象优先在Eden分配 大多数情况下,对象在新生代Eden区中分配.当Eden区中没有足够空间分配时,虚拟机将发起一次Minor GC.虚拟机提供了-XX:PrintGCDetails 这个收集器 ...

  5. AngularJS1.X学习笔记11-服务

    如果我没记错的话,spring里边有个service层.什么是服务呢?个人理解就是很多地方要用的,可以跨越控制器甚至是跨越模块的工具.AngularJS也为我们提供了服务这种机制,这让我们可以将一些不 ...

  6. Linq 集合操作符 Except,Intersect,Union

    IList<string> s1 = new List<string>() { "One", "Two", "Three&qu ...

  7. 非PE病毒介绍

    1.宏病毒 1.1 介绍 本文中的宏特制office系列办公软件中的宏,Microsoft Office中对宏的定义为"宏就是能够组织在一起的,可以作为一个独立命令来执行的一系列Word 命 ...

  8. linux下的Shell编程(3)shell里的流程控制

    if 语句 if 表达式如果条件命令组为真,则执行 then 后的部分.标准形式: if 判断命令,可以有很多个,真假取最后的返回值 then 如果前述为真做什么 [ # 方括号代表可选,别真打进去了 ...

  9. OAuth2.0学习(1-9)新浪开放平台微博认证-web应用授权(授权码方式)

    1. 引导需要授权的用户到如下地址: URL 1 https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&respons ...

  10. 如何修改chrome记住密码后自动填充表单的黄色背景 ?

    input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill { background-color: rgb(2 ...