【BZOJ3110】【codevs1616】K大数查询,权值线段树套普通线段树
来源:互联网 发布:ps中文字体下载mac版 编辑:程序博客网 时间:2024/05/22 08:47
Time:2016.05.09
Author:xiaoyimi
转载注明出处谢谢
传送门1
传送门2
思路:
之前没怎么接触过权值线段树(非主席树),这次就当学习了一下吧。一开始还把题意理解错了,我的天啊……
起初思考了好久,发现不知道怎么处理负数的情况,不过数据里并没有负数?
权值线段树的每个节点表示一个区间[L,R],存储原序列中权值为[L,R]的元素的信息,所以这里的权值线段树每个节点上都是一棵普通线段树,就是负责统计原序列中权值为[L,R]的元素的个数。
每次插入一个相同的值x时就相当于在权值线段树上从根节点一直向下到x所代表的叶子节点,每到权值线段树上的一个节点就修改这个节点所存储的普通线段树的信息
查询时利用二分思想即可(可参见主席树相关练习),但是这里是查询第K大,所以每次折半时计算右子树大小,K大于它就找左边,不然就找右边
注意:
1.代码中采用了标记永久化思想,压小了常数,不过这是我第一次学习使用这个特殊技巧,感觉有些生疏,以后还是要多加练习
(感觉网上对于这个技巧讲述的不多啊!要是那天我熟练了这个技巧了,来写一篇吧)
2.BZOJ上计算总和要无符号整型,不然会爆int,我的天啊……
代码:
#include<bits/stdc++.h>#define M 50005#define ul unsigned intusing namespace std;int n,m,cnt_S,cnt_V,root_S[M<<4],root_V;struct Segment_tree{ ul sum,lazy; int ch[2];}S[M*300];struct Value_tree{ int ch[2];}V[M];int in(){ int t=0,f=1;char ch=getchar(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); } while (isdigit(ch)) t=(t<<3)+(t<<1)+ch-48,ch=getchar(); return f*t;}void S_change(int &rt,int begin,int end,int l,int r){ if (!rt) rt=++cnt_S; if (l<=begin&&end<=r) { S[rt].sum+=end-begin+1; S[rt].lazy++; return; } int mid=begin+end>>1; if (mid>=l) S_change(S[rt].ch[0],begin,mid,l,r); if (mid<r) S_change(S[rt].ch[1],mid+1,end,l,r); S[rt].sum=S[S[rt].ch[0]].sum+S[S[rt].ch[1]].sum+S[rt].lazy*(end-begin+1);}ul S_get(int &rt,int begin,int end,int l,int r){ if (!rt) return 0; if (l<=begin&&end<=r) return S[rt].sum; int mid=begin+end>>1;ul ans=S[rt].lazy*(min(r,end)-max(l,begin)+1); if (mid>=l) ans+=S_get(S[rt].ch[0],begin,mid,l,r); if (mid<r) ans+=S_get(S[rt].ch[1],mid+1,end,l,r); return ans;}void V_change(int &rt,int begin,int end,int x,int y,int z){ if (!rt) rt=++cnt_V; S_change(root_S[rt],1,n,x,y); if (begin==end) return; int mid=begin+end>>1; if (mid>=z) V_change(V[rt].ch[0],begin,mid,x,y,z); else V_change(V[rt].ch[1],mid+1,end,x,y,z);}int V_get(int rt,int begin,int end,int x,int y,int z){ if (begin==end) return end; int mid=begin+end>>1; ul t=S_get(root_S[V[rt].ch[1]],1,n,x,y); if (z<=t) return V_get(V[rt].ch[1],mid+1,end,x,y,z); else return V_get(V[rt].ch[0],begin,mid,x,y,z-t);}main(){ n=in();m=in(); int opt,x,y,z; while (m--) { opt=in();x=in(); y=in();z=in(); if (opt==1) V_change(root_V,1,n,x,y,z); else printf("%lu\n",V_get(root_V,1,n,x,y,z)); }}
0 0
- 【BZOJ3110】【codevs1616】K大数查询,权值线段树套普通线段树
- [BZOJ3110]K大数查询|线段树套线段树
- 【BZOJ3110】【Zjoi2013】K大数查询 树套树 权值线段树套区间线段树
- 【bzoj3110】[Zjoi2013]K大数查询 权值线段树套区间线段树
- 【bzoj3110】【ZJOI2013】【K大数查询】【权值线段树套位置线段树】
- bzoj3110[Zjoi2013]K大数查询 主席树套线段树
- 【线段树套线段树】[ZJOI 2013] bzoj3110 K大数查询
- [BZOJ3110][ZJOI2013]K大数查询(线段树套线段树)
- [BZOJ3110][Zjoi2013]K大数查询(主席树套线段树||整体二分 )
- 【BZOJ3110】K大数查询(ZJOI2013)-整体二分+线段树
- bzoj3110 K大数查询(整体二分+线段树)
- BSOJ3723:ZJOI2013 k大数查询 线段树套线段树
- 【ZJOI2013】K 大数查询 ( 树状数组套线段树 )
- K大数查询——整体二分套线段树
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
- BZOJ3110 K大数查询 【线段树 + 整体二分 或 树套树(非正解)】
- BZOJ 3110(ZJOI K大数查询-线段树套线段树)
- BZOJ 3110: [Zjoi2013]K大数查询|线段树套线段树
- 2.1.第五个实验--数码管测试段码
- Matlab绘图集锦
- Android 百度地图 SDK v3.0.0 (二) 定位与结合方向传感器
- Android通用流行框架大全
- 用户手势检测-GestureDetector使用详解
- 【BZOJ3110】【codevs1616】K大数查询,权值线段树套普通线段树
- 微信支付SDK-两行代码解决支付
- 数据模型代码
- Android开发中将状态栏改变成透明颜色
- 11.View的基础知识
- 搭建适合IOS的HTTP Live Streaming直播系统
- 链表——将单链表从m到n的结点位置翻转
- Ibatis之3个不常用的Query方法
- Android 百度地图 SDK v3.0.0 (一)