[BZOJ3110] [Zjoi2013] K大数查询 (树套树)
Description
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
Input
第一行N,M
接下来M行,每行形如1 a b c或2 a b c
Output
输出每个询问的结果
Sample Input
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
Sample Output
2
1
HINT
【样例说明】
第一个操作 后位置 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
Source
Solution
树套树。。。说难不难,说简单不简单。曾经花了一星期理解内外线段树的关系。。。一直不理解怎么“套”一棵树的
树套树的一般做法是用两个树形结构,外层代表区间,内层代表该区间下的权值信息或其它的什么
相当于一个二维矩阵,一维是区间信息一维是权值信息。
嘛,其实就是外层线段树纪录它对应的内层线段树的节点编号,内层线段树纪录该区间下与某权值范围的的结点信息
为了省空间,需用动态开点的姿势。在这里给各位提个醒:这道题开2000000就好。
嗯= =其实就是把线段树update和query写两遍233
蛋碎了一地。数组开大MLE,数组开小RE。
这道题外层区间内层权值有点麻烦,所以换一种思路:外层权值线段树内层区间线段树。递归查询某一段权值范围内有多少数,若个数小于询问数则向左子树递归,否则向右子树递归。
= =
好吧我的确给别人讲不懂 _(:з」∠)_
代码常熟大地飞起。标记永久化是什么可以吃吗
yky大爷讲了一种奥妙丛丛的压缩空间的方法:把结构体里的变量压缩为x位整型。因为好像存和要用unsigned int于是干脆用long long。具体用法看代码。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct seg1
{
ll l:, r:, sum:, lazy:;
}p1[];
struct operation
{
ll op, l, r, val;
}op[];
ll n, p2[], ptot, cd[], ctot, ql, qr, val; void push_up(ll o, ll l, ll r)
{
p1[o].sum = p1[p1[o].l].sum + p1[p1[o].r].sum + p1[o].lazy * (r - l + );
} void push_down(ll o, ll l, ll r)
{
ll mid = (l + r) >> ;
if(!p1[o].l) p1[o].l = ++ptot;
if(!p1[o].r) p1[o].r = ++ptot;
if(p1[o].lazy)
{
p1[p1[o].l].lazy += p1[o].lazy;
p1[p1[o].r].lazy += p1[o].lazy;
p1[p1[o].l].sum += p1[o].lazy * (mid - l + );
p1[p1[o].r].sum += p1[o].lazy * (r - mid);
p1[o].lazy = ;
}
} void update1(ll o, ll l, ll r)
{
ll mid = (l + r) >> ;
if(ql <= l && r <= qr)
{
p1[o].sum += r - l + , p1[o].lazy++;
return;
}
push_down(o, l, r);
if(ql <= mid) update1(p1[o].l, l, mid);
if(mid < qr) update1(p1[o].r, mid + , r);
push_up(o, l, r);
} void update2(ll o, ll l, ll r)
{
ll mid = (l + r) >> ;
if(!p2[o]) p2[o] = ++ptot;
update1(p2[o], , n);
if(l == r) return;
if(val <= mid) update2(o << , l, mid);
else update2(o << | , mid + , r);
} ll query1(ll o, ll l, ll r)
{
ll mid = (l + r) >> , cnt = ;
if(ql <= l && r <= qr) return p1[o].sum;
push_down(o, l, r);
if(ql <= mid) cnt = query1(p1[o].l, l, mid);
if(mid < qr) cnt += query1(p1[o].r, mid + , r);
return cnt;
} ll query2(ll o, ll l, ll r, ll rk)
{
ll mid = (l + r) >> ;
if(l == r) return l;
if(!p2[o]) p2[o] = ++ptot;
val = query1(p2[o << | ], , n);
if(val < rk) return query2(o << , l, mid, rk - val);
return query2(o << | , mid + , r, rk);
} int main()
{
ll m;
scanf("%lld%lld", &n, &m);
for(ll i = ; i <= m; i++)
{
scanf("%lld%lld%lld%lld", &op[i].op, &op[i].l, &op[i].r, &op[i].val);
if(op[i].op == ) cd[++ctot] = op[i].val;
}
sort(cd + , cd + ctot + );
for(int i = ; i <= m; i++)
if(op[i].op == )
op[i].val = lower_bound(cd + , cd + ctot + , op[i].val) - cd;
for(ll i = ; i <= m; i++)
if(op[i].op == )
{
ql = op[i].l, qr = op[i].r, val = op[i].val;
update2(, , ctot);
}
else
{
ql = op[i].l, qr = op[i].r;
printf("%lld\n", cd[query2(, , ctot, op[i].val)]);
}
return ;
}
[BZOJ3110] [Zjoi2013] K大数查询 (树套树)的更多相关文章
- P3332 [ZJOI2013]K大数查询(线段树套线段树+标记永久化)
P3332 [ZJOI2013]K大数查询 权值线段树套区间线段树 把插入的值离散化一下开个线段树 蓝后每个节点开个线段树,维护一下每个数出现的区间和次数 为了防止MLE动态开点就好辣 重点是标记永久 ...
- BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)
3110 [Zjoi2013]K大数查询 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a ...
- BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3110 题意概括 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位 ...
- BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- bzoj3110: [Zjoi2013]K大数查询 【cdq分治&树套树】
模板题,折腾了许久. cqd分治整体二分,感觉像是把询问分到答案上. #include <bits/stdc++.h> #define rep(i, a, b) for (int i = ...
- 【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数 ...
- BZOJ3110: [Zjoi2013]K大数查询
喜闻乐见的简单树套树= =第一维按权值建树状数组,第二维按下标建动态开点线段树,修改相当于第二维区间加,查询在树状数组上二分,比一般的线段树还短= =可惜并不能跑过整体二分= =另外bzoj上的数据有 ...
- bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】
//========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/ 转载要声明! //=============== ...
- bzoj3110 [Zjoi2013]K大数查询——线段树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 外层权值线段树套内层区间线段树: 之所以外层权值内层区间,是因为区间线段树需要标记下传 ...
随机推荐
- 017 Java中的静态代理、JDK动态代理、cglib动态代理
一.静态代理 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由业务实现类.业务代理类两部分组成.业务实现类负责实现主要的业务方法,业 ...
- 某控股公司OA系统ORACLE DG搭建
*此处安装ORACLE DATAGUARD是利用ORACLE RMAN DUPLICATE方式安装.*可以搭建好ORACLE DG再来impdp生产数据,也可以先导入主库数据再来做DG*注意看下面的配 ...
- Redis入门_下
本文主要介绍redis一些高级特性. 1.Redis HyperLogLog Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常 ...
- CSS布局(二) 盒子模型属性
盒子模型的属性 宽高width/height 在CSS中,可以对任何块级元素设置显式高度. 如果指定高度大于显示内容所需高度,多余的高度会产生一个视觉效果,就好像有额外的内边距一样: 如果指定高度小于 ...
- Python print 输出到控制台 丢数据
import xlrd import sys,time data = xlrd.open_workbook("C:\Users\Administrator\Desktop\\new1.xls ...
- iOS 点击屏幕空白区隐藏键盘方法
iOS开发中,经常要用到输入框,可默认情况下,输入框出来之后,除非点击键盘上面的“Done”或“Next”按钮才能将其隐藏.站在用户体验的角度上看,这种情况很不友好,尤其是不能突显苹果操作的便捷性. ...
- Golang里实现Http服务器并解析header参数和表单参数
在http服务里,header参数和表单参数是经常使用到的,本文主要是练习在Go语言里,如何解析Http请求的header里的参数和表单参数,具体代码如下: package server import ...
- Android开发Toast Notifications
Android开发Toast Notifications 关键类 Toast toast通知是一种在窗口表面弹出的消息.它只占用信息显示所需的空间,用户当前的activity仍保持可见并可交互.该通知 ...
- linux kvm虚拟机快速构建及磁盘类型
KVM命令管理 virsh命令:用来管理各虚拟机的接口命令查看/创建/停止/关闭...支持交互模式格式:virsh 控制指令 [虚拟机名称] [参数] [root@room1pc01 桌面]# vir ...
- 【DDD】领域驱动设计实践 —— 一些问题及想法
在社区系统的DDD实践过程中,将遇到一些问题和产生的想法记录下来,共讨论. 本文为[DDD]系列文章中的其中一篇,其他内容可参考:使用领域驱动设计思想实现业务系统. 1.dto.model和entit ...