博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
zoj 2112 树状数组 套主席树 动态求区间 第k个数
阅读量:4677 次
发布时间:2019-06-09

本文共 6270 字,大约阅读时间需要 20 分钟。

总算是把动态求区间第k个数的算法看明白了。

在主席树的基础上,如果有修改操作,则要通过套树状数组来实现任意区间求第k小的问题。
刚开始看不明白什么意思,现在有一点理解。树状数组的每个元素是一个线段树,来维护修改后的前后缀和,树状数组能在log时间内更整个数组,现在用相同的方式更新整个线段树数组,每次更新一个点时,要更新这个点代表的整个线段树。同样的,求和时用一个use数组记录所要更新的点的下标,每次求不同线段树的同一位置的和。
静态初值不要用来初始化树状数组。
考虑到前缀和,我们通过树状数组来优化,即树状数组套主席树,每个节点都对应一棵主席树,那么修改操作就只要修改logn棵树,
O(nlognlogn+Mlognlogn)时间是可以的,但是直接建树要nlogn*logn(10^7)会MLE。

我们发现对于静态的建树我们只要nlogn个节点就可以了,而且对于修改操作,只是修改M次,每次改变俩个值(减去原先的,加上现

在的)也就是说如果把所有初值都插入到树状数组里是不值得的,所以我们分两部分来做,所有初值按照静态来建,内存O(nlogn),

而修改部分保存在树状数组中,每次修改logn棵树,每次插入增加logn个节点O(M*logn*logn+nlogn)。

离线处理
傻逼题 一直 SF
问题听说 是一定要初始化= =不知都为啥。。傻逼题。。我的代码2 可能在 bzoj 能过。。不清楚。。因为他挂了 代码1是能过的,拿来做板子吧

代码1的方法就是 先建一棵完整的树,就像初始化一样,代码2是直接插入,这样就是树一开始会不一样,代码2默认全部为0,代码1默认一开始的一棵树为0,然后开始改变

代码1:

#include 
#include
#include
#include
#include
using namespace std;typedef long long ll;const int maxn = 5e4+10;int n,m,tot,idx;ll a[maxn],vec[maxn*2];struct{ int x,y,k,flag,idx;} Q[maxn];// 主席树int lson[maxn*50],rson[maxn*50],c[maxn*50],root[maxn]; //依次为左儿子 右儿子 sum 根节点int build (int l,int r){ int root = tot++; c[root] = 0; if (l != r) { int mid = (l + r) >> 1; lson[root] = build(l,mid); rson[root] = build(mid+1,r); } return root;}int update(int root,int pos,int val){ int new_root = tot++; int tmp = new_root; int l = 1,r = idx; c[new_root] = c[root] + val; while (l < r) //用二分而不是递归 减少内存占用 递归可能爆栈 { int mid = (l + r) >> 1; if (pos <= mid) { rson[new_root] = rson[root];// 把旧的右结点赋值到新的右结点 root = lson[root];// 当前的左结点成为新的旧结点 lson[new_root] = tot++;// 创建新的左结点 new_root = lson[new_root]; r = mid; } else { lson[new_root] = lson[root]; root = rson[root]; rson[new_root] = tot++; new_root = rson[new_root]; l = mid + 1; } c[new_root] = c[root] + val;// root 是旧的 new是新的 用旧的更新新的 } return tmp;}// 树状数组维护int s[maxn],use[maxn];inline int lowbit (int x){ return x & -x;}void add(int k,int pos,int d){ while (k <= n) { s[k] = update(s[k],pos,d); k += lowbit(k); }}int sum(int pos){ int res = 0; while (pos) { res += c[lson[use[pos]]]; pos -= lowbit(pos); } return res;}int query(int left,int right,int k){ int l_root = root[left-1]; int r_root = root[right]; for (int i = left-1; i > 0; i -= lowbit(i)) use[i] = s[i]; for (int i = right; i > 0; i -= lowbit(i)) use[i] =s[i]; int l = 1,r = idx; while (l < r)//用二分而不是递归 减少内存占用 递归可能爆栈 { int t = sum(right) - sum(left-1) + c[lson[r_root]] - c[lson[l_root]]; int mid = (l + r) >> 1; if (t >= k) { for (int i = left-1; i > 0; i -= lowbit(i)) use[i] = lson[use[i]]; for (int i = right; i > 0; i -= lowbit(i)) use[i] = lson[use[i]]; l_root = lson[l_root]; r_root = lson[r_root]; r = mid; } else { for (int i = left-1; i > 0; i -= lowbit(i)) use[i] = rson[use[i]]; for (int i = right; i > 0; i -= lowbit(i)) use[i] = rson[use[i]]; l_root = rson[l_root]; r_root = rson[r_root]; k -= t; l = mid + 1; } } return l;}void read(){ scanf ("%d%d",&n,&m); for (int i = 1; i <= n; i++) { scanf ("%lld",a+i); vec[++idx] = a[i]; } for (int i = 0; i < m; i++) { char op[3]; scanf ("%s",op); if (op[0] == 'C') { scanf ("%d%d",&Q[i].x,&Q[i].y); Q[i].flag = 0; vec[++idx] = Q[i].y; } if (op[0] == 'Q') { scanf ("%d%d%d",&Q[i].x,&Q[i].y,&Q[i].k); Q[i].flag = 1; } }}int main(void){ int T; scanf ("%d",&T); while (T--) { idx = tot = 0; read(); sort(vec,vec+idx); //离散化 idx = unique(vec,vec+idx) - vec; root[0] = build(1,idx); for (int i = 1; i <= n; i++) { int tmp = lower_bound(vec+1,vec+idx+1,a[i]) - vec ; root[i] = update(root[i-1],tmp,1); } for (int i = 0; i <= n; i++) s[i] = root[0]; for (int i = 0; i < m; i++) { if (Q[i].flag == 0) { int tmp1 = lower_bound(vec+1,vec+idx+1,a[Q[i].x]) - vec ; int tmp2 = lower_bound(vec+1,vec+idx+1,Q[i].y) - vec ; add(Q[i].x,tmp1,-1); add(Q[i].x,tmp2,1); a[Q[i].x] = Q[i].y; } if (Q[i].flag == 1) { printf("%lld\n",vec[query(Q[i].x,Q[i].y,Q[i].k)]); } } } return 0;}

代码2:

#include 
using namespace std;const int N = 50500;#define lowbit(x) (x)&(-x)int ls[N*40],rs[N*40],sum[N*40];int v[3*N],has[3*N],tmp[3*N];int tot,root[3*N];int sze,a,b;//sze代表总的节点数int LS[3*N],RS[3*N];struct Q{ int flag,l,r,k; int d,x;}q[N];void update(int l,int r,int pre,int &now,int d,int val){ now=++sze; ls[now]=ls[pre]; rs[now]=ls[pre]; sum[now]=sum[pre]+val; if(l==r) return ; int mid=(l+r)>>1; if(d<=mid) update(l,mid,ls[pre],ls[now],d,val); else update(mid+1,r,rs[pre],rs[now],d,val);}int query(int l,int r,int k){ if(l==r) return l; int suml=0,sumr=0; for(int i=0;i
>1; if((sumr-suml)>=k) { for(int i=0;i
0;j-=lowbit(j)) LS[a++]=root[j]; for(int j=q[i].r;j>0;j-=lowbit(j)) RS[b++]=root[j]; printf("%d\n",has[query(1,cnt,q[i].k)] ); } else { int tt=lower_bound(tmp+1,tmp+tot+1,v[q[i].d])-tmp; for(int j=q[i].d;j<=n;j+=lowbit(j)) update(1,cnt,root[j],root[j],tt,-1); v[q[i].d]=q[i].x; int tt1=lower_bound(tmp+1,tmp+tot+1,q[i].x)-tmp; for(int j=q[i].d;j<=n;j+=lowbit(j)) update(1,cnt,root[j],root[j],tt1,1); } } }}

转载于:https://www.cnblogs.com/dabai520/p/7554185.html

你可能感兴趣的文章
SAS基础 -- 逻辑库不存在问题解决
查看>>
Servlet监听器统计在线人数
查看>>
第2章 数字之魅——寻找发帖“水王”
查看>>
eclipse jsp html 格式化 format
查看>>
关于手机端IOS系统微信中虚拟键盘遮挡input输入框问题的解决方案 草稿
查看>>
css3背景、边框、和补丁相关属性 (二)
查看>>
Python--小功能应用
查看>>
别做操之过急的”无效将军”,做实实在在的”日拱一卒”
查看>>
CLS(公共语言规范)的CLSCompliant(跨语言调用)
查看>>
[YTU]_2384 ( 矩形类中运算符重载【C++】)
查看>>
分层抽样(Stratified sampling)
查看>>
从 dig(nslookup) bind —— windows 下的域名解析服务器信息的查看
查看>>
线性滤波器(linear filter)与非线性滤波器(non-linear filter)
查看>>
DTFT、DFT、FFT
查看>>
剪枝法观点下的旅行商问题(TSP)
查看>>
快速排序
查看>>
C#中的get 和 set方法
查看>>
js去除范围内所有标签并显示指定字符串
查看>>
结对项目进度2
查看>>
git + git flow 的简单介绍
查看>>