【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询
2015-03-15 17:09
519 查看
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 51 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
Sample Output
12
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 = 300000 + 10; 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[2][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 = 0; while (x > 0){ 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 == 2) printf(""); return sum(1, x) - sum(0, x) * (n - x); } //整体二分 void solve(int l, int r, int L, int R){ if (l > r || L == R) return; int mid = (L + R) >> 1; for (int i = l; i <= r; i++){ //区间加 if (q[id[i]].type == 1 && q[id[i]].k >= mid){//注意是区间第k大 int a = q[id[i]].l, b = q[id[i]].r; add(0, a, 1); add(0, b + 1, -1); add(1, a, n - a + 1); add(1, b + 1, - (n - (b + 1) + 1)); }else if (q[id[i]].type == 2) tmp[id[i]] = get(q[id[i]].r) - get(q[id[i]].l - 1); } //清楚标记 for (int i = l; i <= r; i++){ if (q[id[i]].type == 1 && q[id[i]].k >= mid){ int a = q[id[i]].l, b = q[id[i]].r; add(0, a, -1); add(0, b + 1, 1); add(1, a, -(n - a + 1)); add(1, b + 1, (n - (b + 1) + 1)); } } int l1 = 0, l2 = 0; //q1放右边,q2放左边 for (int i = l; i <= r; i++){ if (q[id[i]].type == 2){ //这个要放在右边 if (q[id[i]].cur + tmp[id[i]] > q[id[i]].k - 1){ 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 = 1; i <= l2; i++) id[i + l - 1] = q2[i]; for (int i = 1; i <= l1; i++) id[i + l2 + l - 1] = q1[i]; solve(l, l + l2 - 1, L, mid); solve(l + l2, r, mid + 1, R); } void init(){ memset(c, 0, sizeof(c)); scanf("%d%d", &n, &m); cnt = 0;//cnt用来记录询问问题个数 Min = INF, Max = -INF; for (int i = 1; i <= m; i++){ int t; scanf("%d", &t); if (t == 1){//插入操作 int l, r, x; scanf("%d%d%d", &l, &r, &x); q[i].type = 1; q[i].l = l; q[i].r = r; q[i].k = x; q[i].s = 0; q[i].cur = 0; Max = max(Max, x); Min = min(Min, x); }else if (t == 2){//询问操作 int l, r, x; scanf("%d%d%d", &l, &r, &x); q[i].type = 2; q[i].l = l; q[i].r = r; q[i].k = x; q[i].cur = 0; q[i].s = ++cnt;//注意这里x是第k大 } } for (int i = 1; i <= m; i++) id[i] = i; //printf("%d %d\n", Max, Min); } int main(){ int T; init(); solve(1, m, Min, Max + 1); for (int i = 1; i <= cnt; i++) printf("%d\n", Ans[i]); return 0; }
View Code
相关文章推荐
- BZOJ 3110 [Zjoi2013]K大数查询 (整体二分 + 树状数组或线段树处理区间合值)
- 【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改
- 【BZOJ 3110】 [Zjoi2013]K大数查询 整体二分+树状数组区间修改
- bzoj3110 [Zjoi2013]K大数查询(整体二分+线段树)
- BZOJ-4034: [HAOI2015]树上操作 (树链剖分 入门题 子树整体修改 线段树 区间修改+查询)
- 【BZOJ3110】K大数查询(权值线段树套线段树+标记永久化,整体二分)
- BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
- [BZOJ3110][Zjoi2013]K大数查询(主席树套线段树||整体二分 )
- 【BZOJ-3110】K大数查询 整体二分 + 线段树
- BZOJ_3110_[Zjoi2013]K大数查询_整体二分+树状数组
- 【整体二分+树状数组区间加区间和】BZOJ3110 [Zjoi2013]K大数查询
- 【BZOJ3110】K大数查询(ZJOI2013)-整体二分+线段树
- BZOJ3110 K大数查询 【线段树 + 整体二分 或 树套树(非正解)】
- BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
- BZOJ3110 K大数查询 【线段树 + 整体二分 或 树套树(非正解)】
- [BZOJ]3110: [Zjoi2013]K大数查询 整体二分+线段树
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
- 【BZOJ3110】【Zjoi2013】K大数查询 树套树 权值线段树套区间线段树
- BZOJ_P3110 [ZJOI2013]K大数查询(线段树+整体二分)
- 【BZOJ 3110】 [Zjoi2013]K大数查询(整体二分)