3110: [Zjoi2013]K大数查询

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 10703  Solved: 3209
[Submit][Status][Discuss]

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

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

Sample Output

1
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

分析:学习了一波整体二分.

   整体二分不是特别好理解.  我个人的理解是整体二分其实是把二分的权值和若干个操作给关联起来. 普通的二分一次只能回答一个询问,而整体二分能够将所有询问以多一个log的代价在一起处理.

   步骤:在solve函数中完成,需要传递4个参数:L,R,l,r,分别表示操作序列的左右端点以及二分答案的l和r.  操作序列就是把所有的操作放在一个序列里. 题目中给的1~m个操作就组成了一个操作序列,这里只是把这些操作序列给提出来.  l和r就是普通二分中的l和r.

   如果l == r了,那么L到R中所有查询操作的答案都是l.

   否则令mid = (l + r) / 2.这里的mid实际上就是二分的一个答案,接下来要做的事情就是看哪些询问操作的答案等于mid,哪些会大于或小于mid.

   遍历L到R的操作序列.如果当前操作为修改操作,并且添加的数>mid,说明这个操作对我们假定答案为mid的询问操作有影响,那么在线段树中将区间[l[i],r[i]]+1,(l[i],r[i]是题目的输入). 并且加入到数组t2中. 否则加入t1.

   如果为查询操作,查询[l[i],r[i]]的答案. 如果当前要查询第k大的数,之前查询的得到的答案比k小,那么当前查询操作的答案肯定比mid小,加入t1中,并且k -= 查询得到的答案.  否则直接加入t2(答案比mid大).

   t1,t2完成了L到R的操作序列的分组.把对答案<mid的查询操作有影响的修改操作和答案一定<mid的查询操作都放到了t1,另外的放到了t2. 值域对应的发生改变,继续递归下去就能得到答案了. 非常神奇!

   注意:线段树在每一次递归时要清空,不要直接递归清空,放一个覆盖标记即可. 50000 * 50000会爆int,用long long!

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;typedef long long ll;
const ll maxn = 50010;
ll n,m,a[maxn],cnt,ans[maxn],id[maxn],t1[maxn],t2[maxn],cover[maxn << 2];
ll tag[maxn << 2],sum[maxn << 2],L[maxn << 2],R[maxn << 2];struct node
{ll l,r,v,id,opt;
} e[maxn];void pushup(ll o)
{sum[o] = sum[o * 2] + sum[o * 2 + 1];
}void pushdown(ll o)
{if (cover[o] != -1){cover[o * 2] = cover[o * 2 + 1] = cover[o];tag[o * 2] = tag[o * 2 + 1] = sum[o * 2] = sum[o * 2 + 1] = cover[o];cover[o] = -1;}if (tag[o]){tag[o * 2] += tag[o];tag[o * 2 + 1] += tag[o];sum[o * 2] += tag[o] * (R[o * 2] - L[o * 2] + 1);sum[o * 2 + 1] += tag[o] * (R[o * 2 + 1] - L[o * 2 + 1] + 1);tag[o] = 0;}
}void build(ll o,ll l,ll r)
{L[o] = l;R[o] = r;sum[o] = tag[o] = 0;cover[o] = -1;if (l == r)return;ll mid = (l + r) >> 1;build(o * 2,l,mid);build(o * 2 + 1,mid + 1,r);pushup(o);
}void update(ll o,ll l,ll r,ll x,ll y,ll v)
{if (x <= l && r <= y){sum[o] += (r - l + 1) * v;tag[o] += v;return;}pushdown(o);ll mid = (l + r) >> 1;if (x <= mid)update(o * 2,l,mid,x,y,v);if (y > mid)update(o * 2 + 1,mid + 1,r,x,y,v);pushup(o);
}ll query(ll o,ll l,ll r,ll x,ll y)
{if (x <= l && r <= y)return sum[o];pushdown(o);ll mid = (l + r) >> 1,res = 0;if (x <= mid)res += query(o * 2,l,mid,x,y);if (y > mid)res += query(o * 2 + 1,mid + 1,r,x,y);return res;
}void solve(ll L,ll R,ll l,ll r)
{if (L > R)return;if (l == r){for (ll i = L; i <= R; i++){ll temp = id[i];if (e[temp].opt == 2)ans[temp] = l;}return;}ll mid = (l + r) >> 1;cover[1] = 0;ll p1 = 0,p2 = 0;for (ll i = L; i <= R; i++){ll temp = id[i];if (e[temp].opt == 1){if (e[temp].v > mid){update(1,1,n,e[temp].l,e[temp].r,1);t2[++p2] = temp;}elset1[++p1] = temp;}else{ll res = query(1,1,n,e[temp].l,e[temp].r);if (res < e[temp].v){e[temp].v -= res;t1[++p1] = temp;}elset2[++p2] = temp;}}for (ll i = 1; i <= p1; i++)id[L + i - 1] = t1[i];for (ll i = 1; i <= p2; i++)id[L + p1 + i - 1] = t2[i];solve(L,L + p1 - 1,l,mid);solve(L + p1,R,mid + 1,r);
}int main()
{scanf("%lld%lld",&n,&m);for (ll i = 1; i <= m; i++){scanf("%lld%lld%lld%lld",&e[i].opt,&e[i].l,&e[i].r,&e[i].v);id[i] = i;}build(1,1,n);solve(1,m,1,n);for (ll i = 1; i <= m; i++)if (e[i].opt == 2)printf("%lld\n",ans[i]);return 0;
}

转载于:https://www.cnblogs.com/zbtrs/p/8583375.html

bzoj3110 [Zjoi2013]K大数查询相关推荐

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

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

  2. [BZOJ3110] [Zjoi2013]K大数查询

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 9208  Solved: 2737 [Submit][S ...

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

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

  4. BZOJ3110: [Zjoi2013]K大数查询(整体二分)

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

  5. 洛谷 P3332 [ZJOI2013]K大数查询 解题报告

    P3332 [ZJOI2013]K大数查询 题目描述 有\(N\)个位置,\(M\)个操作.操作有两种,每次操作如果是\(\tt{1\ a\ b\ c}\)的形式表示在第\(a\)个位置到第\(b\) ...

  6. P3332 [ZJOI2013]K大数查询(整体二分做法)

    P3332 [ZJOI2013]K大数查询 题意: 题解: 利用整体二分来做,这个题和P3834 [模板]可持久化线段树 2的区别在于本题的修改是区间修改,所以将里面的树状数组改成线段树就行,区间修改 ...

  7. 3110: [Zjoi2013]K大数查询

    3110: [Zjoi2013]K大数查询 https://lydsy.com/JudgeOnline/problem.php?id=3110 分析: 整体二分+线段树. 两种操作:区间加入一个数,区 ...

  8. bzoj 3110: [Zjoi2013]K大数查询(树套树)

    树套树: 本质:一棵树的每个节点套着另一棵树 通常时间复杂度:O(nlog²n) 空间复杂度:因为树的大小是nlogn,而每个节点又有一棵nlogn的树,所以最大空间复杂度为O(n²log²) 但事实 ...

  9. [ZJOI2013]K大数查询

    Description: 给定一个序列,支持两种操作 1.在[L,R]的每个位置上加上一个数 (注意一个位置上有多个数) 2.查询[L,R]上所有数中的第K大 Hint: \(n,m<=5e4\ ...

最新文章

  1. 阿里云API网关相关操作
  2. Direct I/O
  3. MyEclipse 15 集成SVN
  4. 第11天学习Java的笔记(数组注意事项)
  5. 给网游写一个挂吧(二) – 启动外挂上
  6. C# 操作线程的通用类[测试通过]
  7. es multi match_PHP 的ES搜索操作
  8. 将地址强制转换为指针
  9. android studio 更新 Gradle错误解决方法
  10. Merkle Tree与区块链
  11. 牛逼!一款基于SpringBoot的微信点餐系统
  12. Javacv 音视频小工具 - 下载抖音视频
  13. CPU/显卡GPU/CUDA/内存/缓存/SDK/API/DLL【转载整理】
  14. 19上海网络赛 Light bulbs (差分)
  15. 深度解析论文 基于 LSTM 的 POI 个性化推荐框架
  16. python用户输入文字_python中用户输入的关键字
  17. 小白科研笔记:简析图神经网络收敛性的理论证明
  18. Java求1000以内的水仙花数
  19. MicroLab专业的嵌入式开发调试工具集免费试用
  20. 使用dex2jar 与xjad 反编译APK文件,查看源码

热门文章

  1. 无法连接到 visual studio 开发服务器
  2. 软件测试 学习之路 MYSQL安装
  3. React中的高阶组件
  4. html树形结构主从命名,HAP_头⾏/主从结构的实现
  5. Git常用指令——持续补充中
  6. bash中的grep函数_如何在Bash中编写函数
  7. devops 三十六计_DevOps从业人员应遵循的16个博客和新闻通讯
  8. keras 微调整模型_如何围绕微服务调整团队
  9. 真美 | 你破坏Java代码的样子,真美!
  10. Bootstrap列表组支持的组件