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大数查询(整体二分)的更多相关文章

  1. BZOJ.3110.[ZJOI2013]K大数查询(整体二分 树状数组/线段树)

    题目链接 BZOJ 洛谷 整体二分求的是第K小(利用树状数组).求第K大可以转为求第\(n-K+1\)小,但是这样好像得求一个\(n\). 注意到所有数的绝对值\(\leq N\),将所有数的大小关系 ...

  2. BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]

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

  3. BZOJ 3110 [Zjoi2013]K大数查询 ——整体二分

    [题目分析] 整体二分显而易见. 自己YY了一下用树状数组区间修改,区间查询的操作. 又因为一个字母调了一下午. 貌似树状数组并不需要清空,可以用一个指针来维护,可以少一个log 懒得写了. [代码] ...

  4. BZOJ 3110 [ZJOI2013]K大数查询 (整体二分+线段树)

    和dynamic rankings这道题的思想一样 只不过是把树状数组换成线段树区间修改,求第$K$大的而不是第$K$小的 这道题还有负数,需要离散 #include <vector> # ...

  5. BZOJ 3110 [Zjoi2013]K大数查询(整体二分)

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 11654  Solved: 3505[Submit][St ...

  6. BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Sta ...

  7. bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Stat ...

  8. 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 &amp; 3236 [Ahoi2013] 作业 题解

    [原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 978  Solved: 476 Descri ...

  9. BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )

    BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ---------------------------------------------------- ...

  10. BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)

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

随机推荐

  1. Chapter 1 First Sight——32

    The class seemed to drag on longer than the others. 这堂课看起来比别的课要长. Was it because the day was finally ...

  2. IDEA类文件不编译问题

    用IDEA的人遇到过类文件上有个小叉吗? 1.在 .gitignore 里面把这个文件去掉 2.setting->builder->compiler->子目录 去掉不编译的文件

  3. how to download image from any web page in java 下载图片

    http://stackoverflow.com/questions/5882005/how-to-download-image-from-any-web-page-in-java (throws I ...

  4. Struts2(result 流 )下载

    jsp: <body> <a href="stream.action?fileName=psb.jpg">psb</a> <br> ...

  5. 通过纯Java代码从excle中读取数据(为.xlsx文件)

    参考链接: 程序代码: package demo; import java.io.File; import java.io.IOException; import java.io.InputStrea ...

  6. Ansible8:Playbook循环【转】

    在使用ansible做自动化运维的时候,免不了的要重复执行某些操作,如:添加几个用户,创建几个MySQL用户并为之赋予权限,操作某个目录下所有文件等等.好在playbook支持循环语句,可以使得某些需 ...

  7. Qt之操作系统环境

    来源:http://blog.sina.com.cn/s/blog_a6fb6cc90102uy9k.html Qt中操作系统环境,官方解释如下: QStringList QProcess::syst ...

  8. shell脚本字符串截取

    假设有变量 var=http://www.google.com/test.htm 一 # 号截取,删除左边字符,保留右边字符.echo ${var#*//}其中 var 是变量名,# 号是运算符,*/ ...

  9. reactor与proactor模式

    在比较这两个模式之前,我们首先的搞明白几个概念,什么是阻塞和非阻塞,什么是同步和异步. 同步和异步是针对应用程序和内核的交互而言的. 同步是指用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪 ...

  10. mysql免安装版使用方法

    1.下载并解压mysql免安装版至自定义目录 2.添加环境变量 变量名:MYSQL_HOME 变量值:D:\Program Files\mysql-5.6.11-winx64 即为mysql的自定义解 ...