BZOJ 3110:[Zjoi2013]K大数查询(整体二分)
http://www.lydsy.com/JudgeOnline/problem.php?id=3110
题意:……
思路:其实和之前POJ那道题差不多,只不过是换成区间更新,而且是第k大不是第k小,第k大是降序的第k个,在二分询问的时候需要注意和第k小的不同细节。
树状数组比线段树快了几倍,所以说树状数组区间更新区间查询是一个值得学的姿势啊。
看了一下别人的,可以把插入时候的值换成n - x + 1,那么就可以变成找第k小了,输出的时候还要换回来。
线段树:
//9028 kb 7484 ms
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 50010
#define lson rt<<1, l, m
#define rson rt<<1|1, m + 1, r
typedef long long LL;
struct P {
int type, l, r, id; LL val;
P () {}
P (int type, int l, int r, LL val, int id) : type(type), l(l), r(r), val(val), id(id) {}
} q[N], lq[N], rq[N], qq[N];
LL tree[N<<], lazy[N<<], ans[N];
int n; void pushup(int rt) { tree[rt] = tree[rt<<|] + tree[rt<<]; } void pushdown(int rt, int len) {
if(lazy[rt]) {
lazy[rt<<] += lazy[rt]; lazy[rt<<|] += lazy[rt];
tree[rt<<] += lazy[rt] * (len - (len >> )); tree[rt<<|] += lazy[rt] * (len >> );
lazy[rt] = ;
}
} void update(int rt, int l, int r, int L, int R, int val) {
if(L <= l && r <= R) {
tree[rt] += (r - l + ) * val; // 居然漏了+1
lazy[rt] += val; return ;
}
pushdown(rt, r - l + );
int m = (l + r) >> ;
if(L <= m) update(lson, L, R, val);
if(m < R) update(rson, L, R, val);
pushup(rt);
} LL query(int rt, int l, int r, int L, int R) {
if(L <= l && r <= R) return tree[rt];
pushdown(rt, r - l + );
int m = (l + r) >> ;
LL ans = ;
if(L <= m) ans += query(lson, L, R);
if(m < R) ans += query(rson, L, R);
return ans;
} void Solve(int l, int r, int lask, int rask) {
if(rask < lask || r < l) return ;
if(l == r) { for(int i = lask; i <= rask; i++) if(q[i].type == ) ans[q[i].id] = l; return ; }
int mid = (l + r) >> , lcnt = , rcnt = ;
for(int i = lask; i <= rask; i++) {
if(q[i].type == ) {
if(mid >= q[i].val) { // 第k大 = 降序第k个,只更新比当前二分的答案大的
lq[++lcnt] = q[i];
} else {
rq[++rcnt] = q[i];
update(, , n, q[i].l, q[i].r, );
}
} else {
LL num = query(, , n, q[i].l, q[i].r);
if(num >= q[i].val) rq[++rcnt] = q[i];
else {
q[i].val -= num;
lq[++lcnt] = q[i];
}
}
}
for(int i = lask; i <= rask; i++) if(q[i].type == && mid < q[i].val) update(, , n, q[i].l, q[i].r, -);
for(int i = ; i <= lcnt; i++) q[i+lask-] = lq[i];
for(int i = ; i <= rcnt; i++) q[i+lask+lcnt-] = rq[i];
Solve(l, mid, lask, lask + lcnt - );
Solve(mid + , r, lask + lcnt, rask);
} int main() {
int m, a, b, c, d, ins = , ask = ;
scanf("%d%d", &n, &m);
for(int i = ; i <= m; i++) {
scanf("%d%d%d%d", &a, &b, &c, &d);
if(a == ) q[i] = P(a, b, c, d, ++ins);
else q[i] = P(a, b, c, d, ++ask);
}
Solve(, n, , m);
for(int i = ; i <= ask; i++)
printf("%lld\n", ans[i]);
return ;
}
树状数组:
//1828ms 6.7MB
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 50010
#define lson rt<<1, l, m
#define rson rt<<1|1, m + 1, r
typedef long long LL;
struct P {
int type, l, r, id; LL val;
P () {}
P (int type, int l, int r, LL val, int id) : type(type), l(l), r(r), val(val), id(id) {}
} q[N], lq[N], rq[N], qq[N];
LL bit[][N], ans[N];
int n; int lowbit(int x) { return x & (-x); }
void Add(int i, int x, int w) { while(x <= n) bit[i][x] += w, x += lowbit(x); }
LL Sum(int i, int x) { LL ans = ; while(x) ans += bit[i][x], x -= lowbit(x); return ans; }
void update(int l, int r, int w) {
Add(, l, w); Add(, r + , -w); Add(, l, w * l); Add(, r + , -w * (r + ));
}
LL query(int l, int r) {
LL lsum = Sum(, l - ) * l - Sum(, l - );
LL rsum = Sum(, r) * (r + ) - Sum(, r);
return rsum - lsum;
} void Solve(int l, int r, int lask, int rask) {
if(rask < lask || r < l) return ;
if(l == r) { for(int i = lask; i <= rask; i++) if(q[i].type == ) ans[q[i].id] = l; return ; }
int mid = (l + r) >> , lcnt = , rcnt = ;
for(int i = lask; i <= rask; i++) {
if(q[i].type == ) {
if(mid >= q[i].val) { // 第k大 = 降序第k个,只更新比当前二分的答案大的
lq[++lcnt] = q[i];
} else {
rq[++rcnt] = q[i];
update(q[i].l, q[i].r, );
}
} else {
LL num = query(q[i].l, q[i].r);
if(num >= q[i].val) rq[++rcnt] = q[i];
else {
q[i].val -= num;
lq[++lcnt] = q[i];
}
}
}
for(int i = lask; i <= rask; i++) if(q[i].type == && mid < q[i].val) update(q[i].l, q[i].r, -);
for(int i = ; i <= lcnt; i++) q[i+lask-] = lq[i];
for(int i = ; i <= rcnt; i++) q[i+lask+lcnt-] = rq[i];
Solve(l, mid, lask, lask + lcnt - );
Solve(mid + , r, lask + lcnt, rask);
} int main() {
int m, a, b, c, d, ins = , ask = ;
scanf("%d%d", &n, &m);
for(int i = ; i <= m; i++) {
scanf("%d%d%d%d", &a, &b, &c, &d);
if(a == ) q[i] = P(a, b, c, d, ++ins);
else q[i] = P(a, b, c, d, ++ask);
}
Solve(, n, , m);
for(int i = ; i <= ask; i++)
printf("%lld\n", ans[i]);
return ;
}
第k小:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 50010
#define lson rt<<1, l, m
#define rson rt<<1|1, m + 1, r
typedef long long LL;
struct P {
int type, l, r, id; LL val;
P () {}
P (int type, int l, int r, LL val, int id) : type(type), l(l), r(r), val(val), id(id) {}
} q[N], lq[N], rq[N], qq[N];
LL bit[][N], ans[N];
int n; int lowbit(int x) { return x & (-x); }
void Add(int i, int x, int w) { while(x <= n) bit[i][x] += w, x += lowbit(x); }
LL Sum(int i, int x) { LL ans = ; while(x) ans += bit[i][x], x -= lowbit(x); return ans; }
void update(int l, int r, int w) {
Add(, l, w); Add(, r + , -w); Add(, l, w * l); Add(, r + , -w * (r + ));
}
LL query(int l, int r) {
LL lsum = Sum(, l - ) * l - Sum(, l - );
LL rsum = Sum(, r) * (r + ) - Sum(, r);
return rsum - lsum;
} void Solve(int l, int r, int lask, int rask) {
if(rask < lask || r < l) return ;
if(l == r) { for(int i = lask; i <= rask; i++) if(q[i].type == ) ans[q[i].id] = l; return ; }
int mid = (l + r) >> , lcnt = , rcnt = ;
for(int i = lask; i <= rask; i++) {
if(q[i].type == ) {
if(mid >= q[i].val) { // 第k大 = 降序第k个,只更新比当前二分的答案大的
lq[++lcnt] = q[i];
update(q[i].l, q[i].r, );
} else {
rq[++rcnt] = q[i];
}
} else {
LL num = query(q[i].l, q[i].r);
if(num >= q[i].val) lq[++lcnt] = q[i];
else {
q[i].val -= num;
rq[++rcnt] = q[i];
}
}
}
for(int i = lask; i <= rask; i++) if(q[i].type == && mid >= q[i].val) update(q[i].l, q[i].r, -);
for(int i = ; i <= lcnt; i++) q[i+lask-] = lq[i];
for(int i = ; i <= rcnt; i++) q[i+lask+lcnt-] = rq[i];
Solve(l, mid, lask, lask + lcnt - );
Solve(mid + , r, lask + lcnt, rask);
} int main() {
int m, a, b, c, d, ins = , ask = ;
scanf("%d%d", &n, &m);
for(int i = ; i <= m; i++) {
scanf("%d%d%d%d", &a, &b, &c, &d);
if(a == ) q[i] = P(a, b, c, n - d + , ++ins);
else q[i] = P(a, b, c, d, ++ask);
}
Solve(, * n + , , m);
for(int i = ; i <= ask; i++)
printf("%lld\n", n - ans[i] + );
return ;
}
BZOJ 3110:[Zjoi2013]K大数查询(整体二分)的更多相关文章
- BZOJ.3110.[ZJOI2013]K大数查询(整体二分 树状数组/线段树)
题目链接 BZOJ 洛谷 整体二分求的是第K小(利用树状数组).求第K大可以转为求第\(n-K+1\)小,但是这样好像得求一个\(n\). 注意到所有数的绝对值\(\leq N\),将所有数的大小关系 ...
- BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]
有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. N ...
- BZOJ 3110 [Zjoi2013]K大数查询 ——整体二分
[题目分析] 整体二分显而易见. 自己YY了一下用树状数组区间修改,区间查询的操作. 又因为一个字母调了一下午. 貌似树状数组并不需要清空,可以用一个指针来维护,可以少一个log 懒得写了. [代码] ...
- BZOJ 3110 [ZJOI2013]K大数查询 (整体二分+线段树)
和dynamic rankings这道题的思想一样 只不过是把树状数组换成线段树区间修改,求第$K$大的而不是第$K$小的 这道题还有负数,需要离散 #include <vector> # ...
- BZOJ 3110 [Zjoi2013]K大数查询(整体二分)
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 11654 Solved: 3505[Submit][St ...
- BZOJ 3110: [Zjoi2013]K大数查询 [树套树]
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6050 Solved: 2007[Submit][Sta ...
- bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1384 Solved: 629[Submit][Stat ...
- 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 & 3236 [Ahoi2013] 作业 题解
[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 978 Solved: 476 Descri ...
- BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )
BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ---------------------------------------------------- ...
- BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 418 Solved: 235 [ Submit][ ...
随机推荐
- 第二十节,基本数据类型,集合set、综合应用新数据更新老数据
基本数据类型,集合set.综合应用新数据更新老数据 创建两个字典新数据,更新原始数据,a为原始数据,b为新数据 1,分别获取到a字典和b字典的key(键),将两个字典的键分别转换成两个集合 2,找出a ...
- git 忽略已跟踪的文件
对于未跟踪的文件,可以编辑.gitignore文件进行忽略. 对于已跟踪的文件,编辑.gitignore文件不会起作用,它只针对未被跟踪的文件,也就是你先设置规则,然后添加的新文件符合这些规则的就会被 ...
- jQuery第一章
一.jQuery的优势 1.轻量级:压缩之后大小只有30KB左右. 2.强大的选择器:jQuery允许CSS1到CSS3几乎所有的选择器以及自身独创的选择器. 3.出色的DOM操作的封装:jQuery ...
- 修改index.php 清空mylog1.txt
进入编辑php文件vim index.php(无则新建) -->进入命令行模式--输入a(append)-->进入编辑模式-->编辑好-->esc退出编辑模式-->:q! ...
- nefu 943 黑屏
Description Veda 在用宽高比为a:b的显示器看一部宽高比为c:d的电影.在使用全屏模式看电影时,如果这个比例不相同,那么在显示器上就会出现了一些没有画面的地方,我们暂且称之为“黑屏”( ...
- build path contains duplicate entry:'src' for project 'XXX'
解决了,原因是编译器配置不正确,原工程使用adk8/android2.3,我用的是最新的4.0,改了下编译环境就好了.
- Nginx配置IP白名单和黑名单
白名单设置,访问根目录 location / { allow 123.34.22.155; allow ; deny all; } 黑名单设置,访问根目录 location / { deny 123. ...
- 微信支付WxpayAPI_php_v3(一)sdk简介与错误修改
经过断断续续将近一周的时间终于把微信支付调通了. 这里总结一下,算是给后来者有个指引.少踩坑!!!! 开发语言:php5.5 语言框架:laravel5.2 微信sdk:WxpayAPI_php_v3 ...
- Androidndk开发打包时我们应该如何注意平台的兼容(x86,arm,arm-v7a)
很多朋友在开发Android JNI的的时候,会遇到findlibrary returned null的错误,因为某种原因,so没有打包到apk中.下面浅析下引起该错误的原因以及平台兼容性问题. 一. ...
- listener、context、filter、servlet及其加载顺序
首先说加载顺序:context-param—>listener —> filter —> servlet 这四类加载顺序与配置顺序无关,对于每一类内部的加载顺序,与配置顺序有关: l ...