【poj1901-求区间第k大值(带修改)】树状数组套主席树
901: Zju2112 Dynamic Rankings
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 7025 Solved: 2925
[Submit][Status][Discuss]
Description
给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。
Input
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
Output
Sample Input
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
6
HINT
20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。
-------------------------------------------------------------------------------------
嗷嗷嗷A了好海森

首先要回忆一下树状数组的样子。。它是一棵树的结构,也就是一个点只会被另一个点所访问到(父亲只有一个)。
上一题不带修改的主席树中,每一棵树是维护前缀区间1~L的。
这样,要是我们要修改一个数的话,就要把后面的主席树全部修改了。。复杂度变成了m*n*logn,这是不能接受的。
然后大神们就想到了树状数组!
我们修改每一棵主席树维护的区间,对于第i棵主席树,维护树状数组中所对应的lowbit(i)个数。
然后修改就只需要m*logn*logn了。
查询则变成了logn*logn的了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std; const int N=,INF=(int)1e9+;
int n,m,pl,tl,mx;
int a[*N],num[*N],crt[*N],root[*N];
char s[];
struct trnode{
int lc,rc,cnt;
}t[*N];
struct ques{
int l,r,k,x,d;
bool tmp;
}q[N];
struct node{
int d,id;
}p[*N]; bool cmp(node x,node y){return x.d<y.d;} int bt(int l,int r)
{
int x=++tl;
t[x].cnt=;
t[x].lc=t[x].rc=;
if(l<r)
{
int mid=(l+r)/;
t[x].lc=bt(l,mid);
t[x].rc=bt(mid+,r);
}
return x;
} int update(int rt,int p,int d)
{
int now=++tl,tmp=now;
int l=,r=mx,mid;
t[now].cnt=t[rt].cnt+d;
while(l<r)
{
mid=(l+r)/;
if(p<=mid)
{
r=mid;
t[now].lc=++tl;
t[now].rc=t[rt].rc;
rt=t[rt].lc;
now=tl;
}
else
{
l=mid+;
t[now].lc=t[rt].lc;
t[now].rc=++tl;
rt=t[rt].rc;
now=tl;
}
t[now].cnt=t[rt].cnt+d;
}
return tmp;
} void add(int x,int p,int d)
{
for(int i=x;i<=n;i+=(i&(-i))) root[i]=update(root[i],p,d);
} int getsum(int x)
{
int ans=;
for(int i=x;i>=;i-=(i&(-i))) ans+=t[t[crt[i]].lc].cnt;
return ans;
} int query(int lx,int rx,int k)
{
for(int i=lx-;i>=;i-=(i&(-i))) crt[i]=root[i];//多棵树同时走。
for(int i=rx;i>=;i-=(i&(-i))) crt[i]=root[i];
int l=,r=mx,mid,sum;
while(l<r)
{
mid=(l+r)/;
sum=getsum(rx)-getsum(lx-);
if(sum>=k)
{
r=mid;
for(int i=lx-;i>=;i-=(i&(-i))) crt[i]=t[crt[i]].lc;
for(int i=rx;i>=;i-=(i&(-i))) crt[i]=t[crt[i]].lc;
}
else
{
l=mid+;
k-=sum;
for(int i=lx-;i>=;i-=(i&(-i))) crt[i]=t[crt[i]].rc;
for(int i=rx;i>=;i-=(i&(-i))) crt[i]=t[crt[i]].rc;
}
}
return l;
} int main()
{
freopen("a.in","r",stdin);
scanf("%d%d",&n,&m);
pl=n;tl=;
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
p[i].d=a[i];p[i].id=i;
}
for(int i=;i<=m;i++)
{
scanf("%s",s);
if(s[]=='Q')
{
q[i].tmp=;
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
}
else
{
q[i].tmp=;
scanf("%d%d",&q[i].x,&q[i].d);
p[++pl].d=q[i].d;p[pl].id=n+i;
}
}
sort(p+,p++pl,cmp);
mx=;p[].d=INF;
for(int i=;i<=pl;i++)
{
if(p[i].d!=p[i-].d) mx++,num[mx]=p[i].d;
if(p[i].id<=n) a[p[i].id]=mx;
else q[p[i].id-n].d=mx;
}
// for(int i=1;i<=n;i++) printf("%d ",a[i]);printf("\n");
root[]=bt(,mx);
for(int i=;i<=n;i++)
root[i]=root[];
for(int i=;i<=n;i++)
add(i,a[i],);
for(int i=;i<=m;i++)
{
if(q[i].tmp==)
printf("%d\n",num[query(q[i].l,q[i].r,q[i].k)]);
else
{
add(q[i].x,a[q[i].x],-);
add(q[i].x,q[i].d,);
a[q[i].x]=q[i].d;//debug
}
}
return ;
}
【poj1901-求区间第k大值(带修改)】树状数组套主席树的更多相关文章
- ZOJ 2112 Dynamic Rankings(树状数组套主席树 可修改区间第k小)题解
题意:求区间第k小,节点可修改 思路:如果直接用静态第k小去做,显然我更改一个节点后,后面的树都要改,这个复杂度太高.那么我们想到树状数组思路,树状数组是求前缀和,那么我们可以用树状数组套主席树,求出 ...
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- Codeforces Round #404 (Div. 2) E. Anton and Permutation(树状数组套主席树 求出指定数的排名)
E. Anton and Permutation time limit per test 4 seconds memory limit per test 512 megabytes input sta ...
- 【树状数组套主席树】带修改区间K大数
P2617 Dynamic Rankings 题目描述给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+ ...
- 【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树状数组套主席树)
http://www.lydsy.com/JudgeOnline/problem.php?id=1901 首先还是吐槽时间,我在zoj交无限tle啊!!!!!!!!我一直以为是程序错了啊啊啊啊啊啊. ...
- 【BZOJ 1901】【Zju 2112】 Dynamic Rankings 动态K值 树状数组套主席树模板题
达神题解传送门:http://blog.csdn.net/dad3zz/article/details/50638360 说一下我对这个模板的理解: 看到这个方法很容易不知所措,因为动态K值需要套树状 ...
- ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树)
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
- 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))
函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...
- ZOJ 2112 Dynamic Rankings (动态第 K 大)(树状数组套主席树)
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
随机推荐
- PHP 签到,与时间获取,数组长度获取
本文实例讲述了php实现签到功能的方法.分享给大家供大家参考,具体如下:首先我在数据库里建了两张表,一个是用户的积分表,一个是签到状态表,分来用来记录用户的积分数和先到状态 在用户签到状态表中我们有一 ...
- dataTables工作总结
近期在工作中用到了dataTables,现在总结一下在工作中遇到的问题以及解决方法,如有不妥之处希望多多指教,定会改进. 首先这里用的是coloradmin框架,在vs环境下开发. 这里写一个容器用于 ...
- 【log4net】- 非常完善的Log4net详细说明
1.概述 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文主要是介绍如何在Visual S ...
- 【bzoj1606】[Usaco2008 Dec]Hay For Sale 购买干草 背包dp
题目描述 约翰遭受了重大的损失:蟑螂吃掉了他所有的干草,留下一群饥饿的牛.他乘着容量为C(1≤C≤50000)个单位的马车,去顿因家买一些干草. 顿因有H(1≤H≤5000)包干草,每一包都有它的体 ...
- PowerDesigner 建表语句没出现字段描述
填写了Name 还是没有 修改步骤如下:
- I/O复用----select
2018-07-31 (星期二)I/O复用: 一个应用程序通常需要服务一个以上的文件描述符. 例如stdin,stdout,进程间通信以及若干文件进行I/O,如果不借助线程的话,(线程通常 ...
- [洛谷P2511][HAOI2008]木棍分割
题目大意:有$n(n\leqslant5\times10^4)$根木棍,连续放在一起,把它们分成$m(\leqslant10^3)$段,要求使得最长的段最短,问最短的长度以及方案数 题解:要使得最长的 ...
- 【以前的空间】bzoj 1072 [SCOI2007]排列perm
又颓废了一个下午,最近撸mc撸到丧失意识了,玩的有点恶心,于是找水题做,瞧不起颓废的自己啊. another水题. 这题题意很明显啦,就是找数字排列后组成的数去mod d=0后有多少种. 普通的搜索的 ...
- [AHOI2009]中国象棋 DP,递推,组合数
DP,递推,组合数 其实相当于就是一个递推推式子,然后要用到一点组合数的知识 一道很妙的题,因为不能互相攻击,所以任意行列不能有超过两个炮 首先令f[i][j][k]代表前i行,有j列为一个炮,有k列 ...
- 51NOD 1149:Pi的递推式——题解
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1149 F(x) = 1 (0 <= x < 4) F(x) ...