【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询
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
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
Sample Output
2
1
HINT
【样例说明】
第一个操作 后位置 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操作中abs(c)<=Maxlongint
Source
【分析】
我可以吐槽一下数据很水吗?1A了
表示整体二分大法好,离线第K大都不怕。
区间修改用线段树和树状数组都可以水。
/*
明代杨慎
《临江仙·滚滚长江东逝水》 滚滚长江东逝水,浪花淘尽英雄。
是非成败转头空。
青山依旧在,几度夕阳红。
白发渔樵江渚上,惯看秋月春风。
一壶浊酒喜相逢。
古今多少事,都付笑谈中。
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
#include <iomanip>
#include <string>
#include <cmath>
#include <queue>
#include <assert.h>
#include <map>
#include <ctime>
#include <cstdlib>
#include <stack>
#define LOCAL
const int INF = 0x7fffffff;
const int MAXN = + ;
using namespace std;
//整体二分+树状数组的区间修改!
struct QUESTION{
int l, r;
int k, s, cur, type;
}q[MAXN];
int id[MAXN];
int Max, Min, n, m, Ans[MAXN];
int c[][MAXN];//0是普通和,1是全部和
int tmp[MAXN], q1[MAXN], q2[MAXN], cnt; int lowbit(int x) {return x & -x;}
int sum(int k, int x){
int cnt = ;
while (x > ){
cnt += c[k][x];
x -= lowbit(x);
}
return cnt;
}
void add(int k, int x, int val){
while (x <= n){
c[k][x] += val;
x += lowbit(x);
}
return;
}
//得到一个点真实的前缀和
int get(int x){
if (x == )
printf("");
return sum(, x) - sum(, x) * (n - x);
}
//整体二分
void solve(int l, int r, int L, int R){
if (l > r || L == R) return; int mid = (L + R) >> ;
for (int i = l; i <= r; i++){
//区间加
if (q[id[i]].type == && q[id[i]].k >= mid){//注意是区间第k大
int a = q[id[i]].l, b = q[id[i]].r;
add(, a, );
add(, b + , -);
add(, a, n - a + );
add(, b + , - (n - (b + ) + ));
}else if (q[id[i]].type == ) tmp[id[i]] = get(q[id[i]].r) - get(q[id[i]].l - );
}
//清楚标记
for (int i = l; i <= r; i++){
if (q[id[i]].type == && q[id[i]].k >= mid){
int a = q[id[i]].l, b = q[id[i]].r;
add(, a, -);
add(, b + , );
add(, a, -(n - a + ));
add(, b + , (n - (b + ) + ));
}
}
int l1 = , l2 = ;
//q1放右边,q2放左边
for (int i = l; i <= r; i++){
if (q[id[i]].type == ){
//这个要放在右边
if (q[id[i]].cur + tmp[id[i]] > q[id[i]].k - ){
q1[++l1] = id[i];
Ans[q[id[i]].s] = mid;
}else{
q[id[i]].cur += tmp[id[i]];
q2[++l2] = id[i];
}
}else{
if (q[id[i]].k >= mid) q1[++l1] = id[i];
else q2[++l2] = id[i];
}
} for (int i = ; i <= l2; i++) id[i + l - ] = q2[i];
for (int i = ; i <= l1; i++) id[i + l2 + l - ] = q1[i];
solve(l, l + l2 - , L, mid);
solve(l + l2, r, mid + , R);
}
void init(){
memset(c, , sizeof(c));
scanf("%d%d", &n, &m);
cnt = ;//cnt用来记录询问问题个数
Min = INF, Max = -INF;
for (int i = ; i <= m; i++){
int t;
scanf("%d", &t);
if (t == ){//插入操作
int l, r, x;
scanf("%d%d%d", &l, &r, &x);
q[i].type = ;
q[i].l = l; q[i].r = r;
q[i].k = x; q[i].s = ;
q[i].cur = ;
Max = max(Max, x);
Min = min(Min, x);
}else if (t == ){//询问操作
int l, r, x;
scanf("%d%d%d", &l, &r, &x);
q[i].type = ;
q[i].l = l; q[i].r = r;
q[i].k = x; q[i].cur = ;
q[i].s = ++cnt;//注意这里x是第k大
}
}
for (int i = ; i <= m; i++) id[i] = i;
//printf("%d %d\n", Max, Min);
} int main(){
int T; init();
solve(, m, Min, Max + );
for (int i = ; i <= cnt; i++) printf("%d\n", Ans[i]);
return ;
}
【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询的更多相关文章
- 【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数 ...
- 【bzoj5173】[Jsoi2014]矩形并 扫描线+二维树状数组区间修改区间查询
题目描述 JYY有N个平面坐标系中的矩形.每一个矩形的底边都平行于X轴,侧边平行于Y轴.第i个矩形的左下角坐标为(Xi,Yi),底边长为Ai,侧边长为Bi.现在JYY打算从这N个矩形中,随机选出两个不 ...
- 【bzoj3132】上帝造题的七分钟 二维树状数组区间修改区间查询
题目描述 “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵. 第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作. ...
- 【bzoj4540】[Hnoi2016]序列 单调栈+离线+扫描线+树状数组区间修改区间查询
题目描述 给出一个序列,多次询问一个区间的所有子区间最小值之和. 输入 输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数.接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i ...
- 【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询
题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作 ...
- 【树状数组区间修改区间求和】codevs 1082 线段树练习 3
http://codevs.cn/problem/1082/ [AC] #include<bits/stdc++.h> using namespace std; typedef long ...
- 【POJ3468】【树状数组区间修改】A Simple Problem with Integers
Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...
- BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 418 Solved: 235 [ Submit][ ...
- 1082 线段树练习 3 && 树状数组区间修改区间查询
1082 线段树练习 3 题意: 给定序列初值, 要求支持区间修改, 区间查询 Solution 用树状数组, 代码量小, 空间占用小 巧用增量数组, 修改时在 \(l\) 处 $ + val$ , ...
随机推荐
- Linux Shell编程(11)——退出和退出状态
exit命令一般用于结束一个脚本,就像C语言的exit一样.它也能返回一个值给父进程.每一个命令都能返回一个退出状态(有时也看做返回状态).一个命令执行成功返回0,一个执行不成功的命令则返回一个非零值 ...
- KK的新书《必然》对未来科技趋势的预言
是他第一次在<失控>中提示我们-- 要用生物学而不是机械学的角度看待这个世界. 是他第一次在<科技想要什么>提示我们-- 科技本身就是一个生命体. 而在新书<必然 ...
- 博弈论(SG函数):HNOI 2007 分裂游戏
Description 聪聪和睿睿最近迷上了一款叫做分裂的游戏. 该游戏的规则试: 共有 n 个瓶子, 标号为 0,1,2.....n-1, 第 i 个瓶子中装有 p[i]颗巧克力豆,两个人轮流取豆子 ...
- Linux学习笔记16——wait函数
wait函数的定义如下: #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *stat_loc); wai ...
- StoryBoard 的使用
简单入门: http://my.oschina.net/plumsoft/blog/53886 详细操作:http://www.cnblogs.com/buro79xxd/archive/2012/0 ...
- DBI接口和DPI接口的区别
1)DBI接口 A,也就是通常所讲的MCU借口,俗称80 system接口.The lcd interface between host processor and LCM device list a ...
- Apache-POI操作Excel的一些小技巧
Apache-POI操作Excel将合并后的单元格全部填充为相同数据的一个实例. private static void fillMergedRegion(final Sheet sheet) { f ...
- EXCEL VBA运行不显示系统提示
Sub XXX() Application.DisplayAlerts = False '代码段 Application.DisplayAlerts = True End Sub 以下是MICROSO ...
- DevExpress控件 GridControl 单元格编辑 回车
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- C# WinForm 判断窗体控件是否修改过
本文转载:http://www.cnblogs.com/LinFx/archive/2011/12/23/2299895.html 1.自定义控件, 和接口 ) return IsModify(con ...