【ZJOI 2013】 K大数查询 · 续
2013-04-12 20:23
176 查看
· 在线算法弱爆了...
· 分治神器
· Orz小oy
小oy竟然BZOJ rank1了?!
这怎么行呢...~\(≧▽≦)/~
原来说过本题可以用树套树搞定...不过那是在线算法.
今天说说离线算法...
考虑到在线算法是在值域上做二分.
那么同样可以考虑离线二分.
定义solve(L, R), 表示解决答案值域在[L, R]中的询问.
明显我们需要求的是solve(1, n)
考虑调用solve(1, n), 我们可以将所有的操作分为2类:
对于1操作, 如果其修改值≤ n / 2, 归入类1
对于2操作, 如果其答案值域≤ n / 2, 归入类1
这样, 每层我们的任务都是将当前操作分类.
对于1操作, O(1) 可分类.
对于2操作, 我们可以转化为如下问题:
判断[l, r] 中≤ n / 2 的数的个数是否<k
其中l, r为2操作的区间, k为2操作的询问值.
明显, 我们已经将在该操作之前的所有修改值≤ n / 2 的1操作分类过.
只需要维护一个区间和即可.
分类完后递归询问solve(1, n / 2), solve(n / 2 + 1, n), 依次类推即可.
为了常数用树状数组吧.
于是复杂度O(nlog^2n), 常数小得可怕.
特别无聊把小oy压了4ms... ( 有意义么! 你这个大丧失! )
· 分治神器
· Orz小oy
小oy竟然BZOJ rank1了?!
这怎么行呢...~\(≧▽≦)/~
原来说过本题可以用树套树搞定...不过那是在线算法.
今天说说离线算法...
考虑到在线算法是在值域上做二分.
那么同样可以考虑离线二分.
定义solve(L, R), 表示解决答案值域在[L, R]中的询问.
明显我们需要求的是solve(1, n)
考虑调用solve(1, n), 我们可以将所有的操作分为2类:
对于1操作, 如果其修改值≤ n / 2, 归入类1
对于2操作, 如果其答案值域≤ n / 2, 归入类1
这样, 每层我们的任务都是将当前操作分类.
对于1操作, O(1) 可分类.
对于2操作, 我们可以转化为如下问题:
判断[l, r] 中≤ n / 2 的数的个数是否<k
其中l, r为2操作的区间, k为2操作的询问值.
明显, 我们已经将在该操作之前的所有修改值≤ n / 2 的1操作分类过.
只需要维护一个区间和即可.
分类完后递归询问solve(1, n / 2), solve(n / 2 + 1, n), 依次类推即可.
为了常数用树状数组吧.
于是复杂度O(nlog^2n), 常数小得可怕.
特别无聊把小oy压了4ms... ( 有意义么! 你这个大丧失! )
#include <cstdio> #include <cstdlib> #include <algorithm> using namespace std; int n, m, max_i, set; int vis1[50010], vis2[50010]; int right[20][50010], left[20][50010], tot1[50010], tot2[50010]; int a[50010], b[50010], c[50010], d[50010], now[50010], ans[50010]; int toT(int *q, int *p, int x) { int t = 0; for (int i = x; i; i -= i & -i) if (q[i] == set) t += p[i]; else q[i] = set, p[i] = 0; return t; } void add(int *q, int *p, int x, int w) { for (int i = x; i <= max_i; i += i & -i) if (q[i] == set) p[i] += w; else q[i] = set, p[i] = w; } void solve(int cr, int *p, int l, int r) { if (!p[0]) return; int mid = (l + r) >> 1; int *rig = right[cr], *lef = left[cr]; rig[0] = lef[0] = 0; ++set; for (int i = 1; i <= p[0]; ++i) { int I = p[i]; if (a[I] == 1) if (d[I] > mid) rig[++rig[0]] = I; else { add(vis1, tot1, b[I], 1); add(vis2, tot2, b[I], b[I]); add(vis1, tot1, c[I] + 1, -1); add(vis2, tot2, c[I] + 1, -c[I] - 1); lef[++lef[0]] = I; } else { int tot = toT(vis1, tot1, c[I]) * (c[I] + 1) - toT(vis2, tot2, c[I]) - toT(vis1, tot1, b[I] - 1) * b[I] + toT(vis2, tot2, b[I] - 1); if (tot + now[I] < d[I]) now[I] += tot, ans[I] = mid, rig[++rig[0]] = I; else lef[++lef[0]] = I; } } if (l == r) return; solve(cr + 1, lef, l, mid); solve(cr + 1, rig, mid + 1, r); } int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= m; ++i) { scanf("%d %d %d %d", a + i, b + i, c + i, d + i); if (a[i] == 1) d[i] = n - d[i] + 1; right[0][i] = i; } right[0][0] = m; max_i = n; solve(1, right[0], 1, n); for (int i = 1; i <= m; ++i) if (a[i] == 2) printf("%d\n", n - ans[i]); }
相关文章推荐
- [BZOJ 3111] ZJOI 2013 蚂蚁寻路 · 动态规划
- 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 & 3236 [Ahoi2013] 作业 题解
- HDU 5412 CRB and Queries && BZOJ 3110: [Zjoi2013]K大数查询 (整体二分+树状数组/线段树)
- 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 & 3236 [Ahoi2013] 作业 题解
- [BZOJ3110][ZJOI2013]K大数查询
- bzoj3110 [Zjoi2013]K大数查询(整体二分)
- 【整体二分】[ZJOI 2013] bzoj3110 K大数查询
- BZOJ3110 [ZJOI2013] K大数查询(加强数据)
- vs2013 图片背景·全透明背景图
- [BZOJ]3110 K大数查询(ZJOI2013)
- 【ZJOI2013】bzoj3110 K大数查询【解法一】
- BZOJ 3110 ZJOI2013 K大数查询 树套树
- [BZOJ 3110] [Zjoi2013] K大数查询 【树套树】
- BZOJ3110:[ZJOI2013]K大数查询——题解
- BZOJ3110: [Zjoi2013]K大数查询
- [BZOJ3110][Zjoi2013]K大数查询(主席树套线段树||整体二分 )
- BZOJ 3110 【ZJOI2013】 K大数查询
- BZOJ3110: [Zjoi2013]K大数查询
- bzoj3110: [Zjoi2013]K大数查询 【cdq分治&树套树】
- bzoj 3214: [Zjoi2013]丽洁体 贪心&动态规划