BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树
题目描述
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
输入
第一行N,M
接下来M行,每行形如1 a b c或2 a b c
输出
输出每个询问的结果
样例输入
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
样例输出
2
1
提示
【样例说明】
第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1
的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是
1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3
大的数是 1 。
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint
显然一棵线段树或平衡树无法维护这道题的操作,那么考虑树套树。
一开始可能会想将维护序列的线段树放在外层,然后将维护序列每个点各种权值的权值线段树放在内层。
这样修改操作就是外层线段树区间修改,内层线段树单点修改,很好操作。
但你发现无法完成询问操作,如果用二分答案来解决的话时间复杂度就是O(nlogn^3)的了。
既然询问第k大,那么显然权值线段树对于这种操作更为擅长,我们将权值线段树放在外层,将维护序列的线段树放在内层。
这样修改就变成了外层线段树单点修改,内层线段树区间修改,同样很好操作。
对于询问,我们每查询到权值线段树的一个节点先在这个点左子节点的内层线段树上区间查找,即找出序列上询问区间中权值小于某个值的数量,再与k判断来决定往左走还是往右走。
- #include<set>
- #include<map>
- #include<queue>
- #include<stack>
- #include<cmath>
- #include<bitset>
- #include<vector>
- #include<cstdio>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- #define ll long long
- using namespace std;
- int n,m;
- int opt;
- int cnt;
- int a,b;
- ll c;
- ll s[20000010];
- int root[2000010];
- ll sum[20000010];
- int ls[20000010];
- int rs[20000010];
- inline void pushup(int rt)
- {
- sum[rt]=sum[ls[rt]]+sum[rs[rt]];
- }
- inline void pushdown(int rt,int l,int r)
- {
- if(s[rt])
- {
- int mid=(l+r)>>1;
- if(!ls[rt])
- {
- ls[rt]=++cnt;
- }
- if(!rs[rt])
- {
- rs[rt]=++cnt;
- }
- s[ls[rt]]+=s[rt];
- s[rs[rt]]+=s[rt];
- sum[ls[rt]]+=s[rt]*(mid-l+1);
- sum[rs[rt]]+=s[rt]*(r-mid);
- s[rt]=0;
- }
- }
- inline void change(int &rt,int l,int r,int L,int R)
- {
- if(!rt)
- {
- rt=++cnt;
- }
- if(L<=l&&r<=R)
- {
- sum[rt]+=(r-l+1);
- s[rt]++;
- return ;
- }
- pushdown(rt,l,r);
- int mid=(l+r)>>1;
- if(L<=mid)
- {
- change(ls[rt],l,mid,L,R);
- }
- if(R>mid)
- {
- change(rs[rt],mid+1,r,L,R);
- }
- pushup(rt);
- }
- inline ll find(int rt,int l,int r,int L,int R)
- {
- if(!rt)
- {
- return 0;
- }
- if(L<=l&&r<=R)
- {
- return sum[rt];
- }
- pushdown(rt,l,r);
- int mid=(l+r)>>1;
- ll res=0;
- if(L<=mid)
- {
- res+=find(ls[rt],l,mid,L,R);
- }
- if(R>mid)
- {
- res+=find(rs[rt],mid+1,r,L,R);
- }
- return res;
- }
- inline void insert(int rt,int l,int r,int k,int L,int R)
- {
- change(root[rt],1,n,L,R);
- if(l==r)
- {
- return ;
- }
- int mid=(l+r)>>1;
- if(k<=mid)
- {
- insert(rt<<1,l,mid,k,L,R);
- }
- else
- {
- insert(rt<<1|1,mid+1,r,k,L,R);
- }
- }
- inline int query(int rt,int l,int r,ll k,int L,int R)
- {
- if(l==r)
- {
- return l;
- }
- int mid=(l+r)>>1;
- ll res=find(root[rt<<1|1],1,n,L,R);
- if(res<k)
- {
- return query(rt<<1,l,mid,k-res,L,R);
- }
- else
- {
- return query(rt<<1|1,mid+1,r,k,L,R);
- }
- }
- int main()
- {
- scanf("%d%d",&n,&m);
- for(int i=1;i<=m;i++)
- {
- scanf("%d",&opt);
- scanf("%d%d%lld",&a,&b,&c);
- if(a>b)
- {
- swap(a,b);
- }
- if(opt==1)
- {
- c=(int)c;
- insert(1,0,2*n,c+n,a,b);
- }
- else
- {
- printf("%d\n",query(1,0,2*n,c,a,b)-n);
- }
- }
- }
BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树的更多相关文章
- 【bzoj3110】[Zjoi2013]K大数查询 权值线段树套区间线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数 ...
- 洛谷P3332 [ZJOI2013]K大数查询 权值线段树套区间线段树_标记永久化
Code: #include <cstdio> #include <algorithm> #include <string> #include <cstrin ...
- [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)
[BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...
- BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)
3110 [Zjoi2013]K大数查询 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a ...
- bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】
//========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/ 转载要声明! //=============== ...
- BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3110 题意概括 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位 ...
- bzoj3110 [Zjoi2013]K大数查询——线段树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 外层权值线段树套内层区间线段树: 之所以外层权值内层区间,是因为区间线段树需要标记下传 ...
- BZOJ3110: [Zjoi2013]K大数查询
喜闻乐见的简单树套树= =第一维按权值建树状数组,第二维按下标建动态开点线段树,修改相当于第二维区间加,查询在树状数组上二分,比一般的线段树还短= =可惜并不能跑过整体二分= =另外bzoj上的数据有 ...
- [BZOJ3110] [Zjoi2013] K大数查询 (树套树)
Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置 ...
随机推荐
- QT数据类型的转化总结
QT 中的数据类型有很多的,在写代码的过程中难免会遇到 数据类型的转换. 1.QString转QByteArray QByteArray byte;QString string;byte = stri ...
- MySQL(十一)视图及存储过程
一.视图 视图是虚拟的表,它只包含使用时动态检索数据的查询. 1.使用视图的好处 ①重用SQL语句: ②简化复杂的SQL操作(可以方便的重用它而不必知道它的基本查询细节): ③使用表的组成部分而不是整 ...
- x509: certificate signed by unknown authority harbor 架构图
默认时,client 与 Registry 的交互是通过 https 通信的.在 install Registry 时,若未配置任何tls 相关的 key 和 crt 文件,https 访问必然失败. ...
- 驱动笔记 - platform中断程序
platform_device: #include <linux/module.h> #include <linux/types.h> #include <linux/f ...
- python_第一章
从今天开始,正式开始学习python书籍:python 编程:从入门到实践. 感兴趣的读者可以去网上搜索这本书,适合读者入门,读下来,不会有任何 晦涩难懂的知识. 1.排序: 正排:sort() ...
- HNOI2016做题笔记
HNOI2016 最小公倍数 (分块.并查集) 看到这种不能用数据结构(实际上是可以用K-D Tree的)维护的题目就应该想到分块然后使用并查集维护连通性和一个连通块中的\(maxa , maxb\) ...
- International Programming Retreat Day(2018.11.17)
时间:2018.11.17地点:北京国华投资大厦
- Python高级特性(切片,迭代,列表生成式,生成器,迭代器)
掌握了Python的数据类型.语句和函数,基本上就可以编写出很多有用的程序了. 比如构造一个1, 3, 5, 7, ..., 99的列表,可以通过循环实现: L = [] n = 1 while n ...
- zabbix邮件报警功能的验证
zabbix里面设置了很多监控项,有很多重要的监控预警,必须保证zabbix邮件报警功能正常,以确保那些告警信息能及时发送到运维人员的邮箱里. 所以需要每天8:30发一封确认zabbix邮件报警功能正 ...
- curator 分布式锁InterProcessMutex
写这篇文章的目的主要是为了记录下自己在zookeeper 锁上踩过的坑,以及踩坑之后自己的一点认识; 从zk分布式锁原理说起,原理很简单,大家也应该都知道,简单的说就是zookeeper实现分布式锁是 ...