题目描述

有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

输出

输出每个询问的结果

样例输入

2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3

样例输出

1
2
1


题解

本蒟蒻并不会写整体二分,所以写了树套树

17.12.23 UPD:比树套树优雅到不知哪里去了的整体二分题解

其实这道题想到方法的话实现起来还是非常容易的。

注意题目中说的是“每个位置加入一个数c”,不是“加上”,也就是说不必支持修改,但必须支持插入。

所以需要选择权值线段树或Treap。

如果把权值线段树或Treap放在内层,区间线段树放在外层,那么会不方便查询(详见 bzoj3194 中子任务2),时间复杂度为O(nlog^3n),TLE;同时也不便于修改。

所以不能把权值线段树或Treap放在内层,必须放在外层,外层就只能选择权值线段树。

把权值线段树放在外层,区间线段树放在内层的话,每个最内层节点表示区间内权值在指定范围内的数的个数。

这样修改时在外层查找对应区间,在内层区间+1,使用lazy标记可以保证时间复杂度。

查询时查的是第k大,所以需要先确定范围。如果权值线段树的右子树对应的区间线段树的区间和(线段树区间查询)大于等于k,即右半部分权值中含有k大数,则在右边查找;否则在左边查找。

注意要把两棵树分开(表示代码可能分的不太清楚。。。),千万不要弄混。

在我的代码中,外层权值线段树是用一般的完全二叉树储存方式(x<<1,x<<1|1),而内层区间线段树是用动态开点的储存方式。

而这里的pushdown、update和query这前三个函数是内层区间线段树的函数;modify、solve是外层权值线段树的函数。

另外,数据经加强后会有负数,所以应把原数+n+1处理。

另外,本题会爆int,而long long可能会TLE,最好是用unsigned int。

#include <cstdio>
#include <algorithm>
#define N 1000010
#define M 20000010
using namespace std;
int n , root[N] , ls[M] , rs[M] , tot;
unsigned sum[M] , tag[M];
void pushdown(int l , int r , int x)
{
if(tag[x])
{
int mid = (l + r) >> 1;
if(!ls[x]) ls[x] = ++tot;
if(!rs[x]) rs[x] = ++tot;
sum[ls[x]] += (mid - l + 1) * tag[x] , tag[ls[x]] += tag[x];
sum[rs[x]] += (r - mid) * tag[x] , tag[rs[x]] += tag[x];
tag[x] = 0;
}
}
void update(int b , int e , int l , int r , int &x)
{
if(!x) x = ++tot;
if(b <= l && r <= e)
{
sum[x] += (r - l + 1) , tag[x] ++ ;
return;
}
pushdown(l , r , x);
int mid = (l + r) >> 1;
if(b <= mid) update(b , e , l , mid , ls[x]);
if(e > mid) update(b , e , mid + 1 , r , rs[x]);
sum[x] = sum[ls[x]] + sum[rs[x]];
}
unsigned query(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e) return sum[x];
pushdown(l , r , x);
int mid = (l + r) >> 1;
unsigned ans = 0;
if(b <= mid) ans += query(b , e , l , mid , ls[x]);
if(e > mid) ans += query(b , e , mid + 1 , r , rs[x]);
return ans;
}
void modify(int b , int e , int p , int l , int r , int x)
{
update(b , e , 1 , n , root[x]);
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) modify(b , e , p , l , mid , x << 1);
else modify(b , e , p , mid + 1 , r , x << 1 | 1);
}
int solve(int b , int e , unsigned a , int l , int r , int x)
{
if(l == r) return l;
int mid = (l + r) >> 1;
unsigned tmp = query(b , e , 1 , n , root[x << 1 | 1]);
if(tmp >= a) return solve(b , e , a , mid + 1 , r , x << 1 | 1);
else return solve(b , e , a - tmp , l , mid , x << 1);
}
int main()
{
int m , opt , x , y , z;
unsigned t;
scanf("%d%d" , &n , &m);
while(m -- )
{
scanf("%d%d%d" , &opt , &x , &y);
if(opt == 1) scanf("%d" , &z) , modify(x , y , z + n + 1 , 1 , 2 * n + 1 , 1);
else scanf("%u" , &t) , printf("%d\n" , solve(x , y , t , 1 , 2 * n + 1 , 1) - n - 1);
}
return 0;
}

【bzoj3110】[Zjoi2013]K大数查询 权值线段树套区间线段树的更多相关文章

  1. BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树

    题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...

  2. 洛谷P3332 [ZJOI2013]K大数查询 权值线段树套区间线段树_标记永久化

    Code: #include <cstdio> #include <algorithm> #include <string> #include <cstrin ...

  3. [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)

    [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...

  4. BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)

    3110 [Zjoi2013]K大数查询 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a ...

  5. BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3110 题意概括 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位 ...

  6. [BZOJ3110] [Zjoi2013] K大数查询 (树套树)

    Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置 ...

  7. bzoj3110 [Zjoi2013]K大数查询——线段树套线段树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 外层权值线段树套内层区间线段树: 之所以外层权值内层区间,是因为区间线段树需要标记下传 ...

  8. BZOJ3110: [Zjoi2013]K大数查询

    喜闻乐见的简单树套树= =第一维按权值建树状数组,第二维按下标建动态开点线段树,修改相当于第二维区间加,查询在树状数组上二分,比一般的线段树还短= =可惜并不能跑过整体二分= =另外bzoj上的数据有 ...

  9. bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】

    //========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/  转载要声明! //=============== ...

随机推荐

  1. Java设计模式(14)——行为模式之不变模式(Immutable)

    一.概述 概念 分类:弱不变模式(子类可变)和强不变模式(子类也是不可变) 应用场景 java.lang.String是一个经典的强不变类 二.分析 与享元模式的关系

  2. Java面向对象之抽象方法&接口

    在开始写抽象类之前,有一个问题我觉得想清楚会对理解抽象类很有帮助:那就是为什么要设计抽象类? 难道用类还不够么,为什么要设计出抽象类这样一个东西.我们可以换个角度来理解,就是有些类本来就是不应该被实例 ...

  3. git 取消commit

    git如何撤销上一次commit操作 1.第一种情况:还没有push,只是在本地commit git reset --soft|--mixed|--hard <commit_id> git ...

  4. react-native windows系统 红屏报assets缺失 500错误

    指定版本,react-native是facebook用mac系统开发的,windows系统兼容较差,新版本更是问题很多, 相对老版本更加稳定 react-native init demo --vers ...

  5. Qt-第一个QML程序-2-关键代码分析,TEXT,Image,Mouseare

    qml语言开始写的时候有点不习惯,后面用的多了感觉很好,很顺手,用于快速搭建项目界面,真的很好. 目前用到的还是比较简单的 隐藏标题栏,而依附任务栏 flags: Qt.Window | Qt.Fra ...

  6. Qt-第一个QML程序-1-项目工程的建立

    这个小程序是我发的第一个完整的QMl程序,这个程序也会持续的更新,一步一步的完善起来,最后会有一个什么样的结果也是不知道,只是把自己目前掌握的QML相关的东西都慢慢的写进来,积累起来 先展示一下运行结 ...

  7. 怎样通过Qt编写C/C++代码查询当前Linux的版本号?

    遇到一个问题:如题. 我的开发环境是:嵌入式ARM + Linux系统 + Qt 4.5 + C/C++ 现在需要查询 当前Linux系统的版本号. 问题: 1)Qt 4.5 提供怎样的API来获取? ...

  8. python学习笔记02 --------------基础数据类型

    python的基本数据类型: 1.基本数据 1.1. 数字类型 1.1.1 整数 int int()           #将括号内内容转化为整数类型. 1.1.2 浮点数 float 1.1.3 复 ...

  9. react项目总结

    1.基本框架 1.react+react-router4+redux3.7.2 2.css预编译使用sass 3.数据请求使用axios(原本是使用fetch,结果在ios10下报错) 4.ui组件库 ...

  10. 哈希表 -数据结构(C语言实现)

    读数据结构与算法分析 哈希表 一种用于以常数平均时间执行插入.删除和查找操作的数据结构. 但是是无序的 一般想法 通常为一个包含关键字的具有固定大小的数组 每个关键字通过散列函数映射到数组中 冲突:两 ...