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][ ...
随机推荐
- hdu_5769_Substring(后缀数组)
题目链接:hdu_5769_Substring 题意: 给你一个字符a和一个串b,问你有多少个包括a的字串 题解: #include<bits/stdc++.h> #define F(i, ...
- 模拟post请求-->测试api是否可用-->再交给ios开发
提交给iso开发前.先模拟post提交,测试返回是否正确 =============post.php文件 ios每次最少要提交5个数据, 加密串 seqno , 请求验证码 source, 设备唯一标 ...
- LeetCode OJ 100. Same Tree
Given two binary trees, write a function to check if they are equal or not. Two binary trees are con ...
- Git add和commit步骤分析
修改后或者添加新的文件,执行add命令后,首先它会先存入本地库的暂存区, add可以上传很多个文件,然后执行commit命令后,都会被提交到默认的分支 Master分支上.只有文件更改和文件新建,都可 ...
- 第5章 字符串----char与String
1.java有8种基本数据类型: 数值型:整数类型(byte,short,int,long) :浮点类型(float,double) 字符型:char 布尔型:true,false 2.char: ...
- 妙用transform
往前移动 transform.Translate transform.Translate( transform.up* speed*Time.deltaTime , Space.World); 移动t ...
- Spring Security3实现,权限动态获取
Spring Security3实现,权限动态获取 原文 http://blog.csdn.net/yangwei19680827/article/details/9359113 主题 网络安全Sp ...
- Android:SQLite无法update/insert/delete数据(数据库被locked)
//在频繁范围数据库进行读写操作后,会发生增删改数据都无效的问题,查询一般正常. mDatabase.beginTransaction(); try { Log.v(TAG,"locked: ...
- 11g init DB software and database
oadmin->administrator2.169set ORACLE_HOME=C:\app\oracle\product\11.2.0\dbhome_1set ORACLE_SID=csm ...
- Gym 100917L Liesbeth and the String 规律&&胡搞
题目: Description standard input/outputStatements Little Liesbeth likes to play with strings. Initiall ...