博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ 3065 带插入区间第K小值
阅读量:4958 次
发布时间:2019-06-12

本文共 7099 字,大约阅读时间需要 23 分钟。

题目描述

Description

从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i]。跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴。这时跳蚤国王决定理性愉悦一下,查询区间k小值。他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少。

这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问。
这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少。
这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问。(orz 主席树)
这时伏特发现有些迟到的跳蚤会插入到这一行的某个位置上,他感到非常生气,因为……他不会做了。
请你帮一帮伏特吧。
快捷版题意:带插入、修改的区间k小值在线查询。

Input

第一行一个正整数n,表示原来有n只跳蚤排成一行做早操。

第二行有n个用空格隔开的非负整数,从左至右代表每只跳蚤的弹跳力。
第三行一个正整数q,表示下面有多少个操作。
下面一共q行,一共三种操作对原序列的操作:(假设此时一共m只跳蚤)

  1. Q x y k: 询问从左至右第x只跳蚤到从左至右第y只跳蚤中,弹跳力第k小的跳蚤的弹跳力是多少。
    (1 <= x <= y <= m, 1 <= k <= y - x + 1)
  2. M x val: 将从左至右第x只跳蚤的弹跳力改为val。
    (1 <= x <= m)
  3. I x val: 在从左至右第x只跳蚤的前面插入一只弹跳力为val的跳蚤。即插入后从左至右第x只跳蚤是我刚插入的跳蚤。
    (1 <= x <= m + 1)

为了体现在线操作,设lastAns为上一次查询的时候程序输出的结果,如果之前没有查询过,则lastAns = 0。

则输入的时候实际是:
Q _x _y _k ------> 表示 Q _x^lastAns _y^lastAns _k^lastAns
M _x _val ------> 表示 M _x^lastAns _val^lastAns
I _x _val ------> 表示 I _x^lastAns _val^lastAns
简单来说就是操作中输入的整数都要异或上一次询问的结果进行解码。

(祝Pascal的同学早日转C++,就不提供pascal版的描述了。)

Sample Input

1010 5 8 28 0 19 2 31 1 22 30I 6 9M 1 11I 8 17M 1 31M 6 26Q 2 7 6I 23 30M 31 7I 22 27M 26 18Q 26 17 31I 5 2I 18 13Q 3 3 3I 27 19Q 23 23 30Q 5 13 5I 3 0M 15 27Q 0 28 13Q 3 29 11M 2 8Q 12 5 7I 30 19M 11 19Q 17 8 29M 29 4Q 3 0 12I 7 18M 29 27

Sample Output

282310141514271514

题目大意

略.

题解

替罪羊树模板题.

用一棵替罪羊树维护序列, 每个节点上开一棵线段树, 维护以这个点为根的子树下的所有权值.
考虑以下操作:

  • 插入: 直接在替罪羊树上插入即可, 正常重建.
  • 修改: 直接修改.
  • 查询: 这个比较麻烦. 我的做法是在替罪羊树上找到所有被这个区间覆盖的点, 分为以下两类
    • 这个点以及以它为根的子树都被题目所求区间包含, 则将这个点上的线段树扔进vector中;
    • 这个点被区间包含, 但并非以它为根的子树都被包含, 则在一棵另开的线段树上插入这个点对应的序列上的权值, 并递归其子树.

 在得到的最多\(\log n\)棵线段树上二分即可

这样的做法是可以保证时空复杂度均为\(n \log^2 n\), 还是可以接受的.

注意空间释放的问题, 我只会写动态的指针式写法, 有些大佬说可以用数组静态模拟, 但我没想懂怎么释放内存, 总之就是不会.
代码跑得很慢, 可能是频繁申请 / 释放空间导致的吧

#include 
#include
#include
#include
namespace Zeonfai{ inline int getInt() { int a = 0, sgn = 1; char c; while(! isdigit(c = getchar())) if(c == '-') sgn *= -1; while(isdigit(c)) a = a * 10 + c - '0', c = getchar(); return a * sgn; } inline char getChar() { char c; while(! isgraph(c = getchar())); return c; } inline void print(int a) { if(! a) return; print(a / 10); putchar(a % 10 + '0'); } inline void println(int a) { if(a < 0) putchar('-'), a *= -1; if(a == 0) putchar('0'); print(a); putchar('\n'); }} const int N = 35000, Q = 35000, BND = 70000;const double ALPH = 0.75;std::vector
cpy; struct segmentTree{ struct node { node* suc[2]; int sum; inline node() { suc[0] = suc[1] = NULL; sum = 0; } }; node* rt; inline segmentTree() { rt = NULL; } node* modify(node* u, int opt, int L, int R, int w) { if(u == NULL) u = new node; u->sum += opt; if(L ^ R) { int mid = L + R >> 1; if(w <= mid) u->suc[0] = modify(u->suc[0], opt, L, mid, w); else u->suc[1] = modify(u->suc[1], opt, mid + 1, R, w); } return u; } inline void modify(int pos, int opt) { rt = modify(rt, opt, 0, BND, pos); } inline void insert(int w) { rt = modify(rt, 1, 0, BND, w); } void clear(node *u) { for(int i = 0; i < 2; ++ i) if(u->suc[i] != NULL) clear(u->suc[i]); delete u; } inline void clear() { if(rt != NULL) clear(rt), rt = NULL; } inline void Delete() { clear(); delete this; }};segmentTree sgt; std::vector
nd, _nd; struct scapegoatTree{ struct node { node *suc[2]; int sz, w; segmentTree *rec; inline node(int _w) { sz = 0, w = _w; suc[0] = suc[1] = NULL; rec = new segmentTree; } inline int check() { int sucSz[2] = {0, 0}; for(int i = 0; i < 2; ++ i) if(suc[i] != NULL) sucSz[i] = suc[i]->sz; return std::max(sucSz[0], sucSz[1]) > sz * ALPH; } }; node *rt; node* build(int L, int R) { int mid = L + R >> 1; node *u = new node(cpy[mid]); if(L < mid) u->suc[0] = build(L, mid - 1); if(R > mid) u->suc[1] = build(mid + 1, R); for(int i = L; i <= R; ++ i) u->rec->insert(cpy[i]), ++ u->sz; return u; } int flg; void DFS(node* u) { u->rec->Delete(); if(u->suc[0] != NULL) DFS(u->suc[0]); cpy.push_back(u->w); if(u->suc[1] != NULL) DFS(u->suc[1]); delete u; } inline node* rebuild(node *u) { cpy.clear(); DFS(u); u = build(0, cpy.size() - 1); flg = 1; return u; } node* insert(node* u, int pos, int w) { int tmp = u == NULL || u->suc[0] == NULL ? 0 : u->suc[0]->sz; if(u == NULL) u = new node(w); else if(pos <= tmp + 1) u->suc[0] = insert(u->suc[0], pos, w); else u->suc[1] = insert(u->suc[1], pos - tmp - 1, w); ++ u->sz; u->rec->insert(w); if(u->check()) u = rebuild(u); return u; } inline void insert(int pos, int w) { flg = 0; rt = insert(rt, pos, w); } void get(node* u, int L, int R) { if(L == 1 && R == u->sz) { nd.push_back(u->rec->rt); return; } int tmp = u->suc[0] == NULL ? 0 : u->suc[0]->sz; if(tmp + 1 >= L && tmp + 1 <= R) sgt.insert(u->w); if(u->suc[0] != NULL && L <= tmp) get(u->suc[0], L, std::min(tmp, R)); if(u->suc[1] != NULL && R >= tmp + 2) get(u->suc[1], std::max(L, tmp + 2) - tmp - 1, R - tmp - 1); } inline int query(int x, int y, int k) { nd.clear(); sgt.clear(); get(rt, x, y); if(sgt.rt != NULL) nd.push_back(sgt.rt); int L = 0, R = BND; while(L ^ R) { int cnt = nd.size(), sum = 0; for(int i = 0; i < cnt; ++ i) sum += nd[i]->suc[0] == NULL ? 0 : nd[i]->suc[0]->sum; _nd.clear(); for(int i = 0; i < cnt; ++ i) if(nd[i]->suc[sum < k] != NULL) _nd.push_back(nd[i]->suc[sum < k]); nd = _nd; if(sum >= k) R = (L + R) >> 1; else L = ((L + R) >> 1) + 1, k -= sum; } return L; } int modify(node* u, int pos, int w) { int tmp = u->suc[0] == NULL ? 0 : u->suc[0]->sz; if(pos == tmp + 1) { u->rec->modify(u->w, -1), u->rec->modify(w, 1); int res = u->w; u->w = w; return res; } int res; if(u->suc[0] != NULL && pos <= u->suc[0]->sz) res = modify(u->suc[0], pos, w); else res = modify(u->suc[1], pos - tmp - 1, w); u->rec->modify(res, -1), u->rec->modify(w, 1); return res; } inline void modify(int pos, int w) { modify(rt, pos, w); }}seq; int main(){ #ifndef ONLINE_JUDGE freopen("BZOJ3065.in", "r", stdin); freopen("BZOJ3065.out", "w", stdout); #endif using namespace Zeonfai; int n = getInt(); for(int i = 0; i < n; ++ i) cpy.push_back(getInt()); seq.rt = seq.build(0, n - 1); int Q = getInt(), lst = 0; for(int i = 0; i < Q; ++ i) { char opt = getChar(); if(opt == 'I') { int pos = getInt() ^ lst, w = getInt() ^ lst; seq.insert(pos, w); } else if(opt == 'Q') { int x = getInt() ^ lst, y = getInt() ^ lst, k = getInt() ^ lst; println(lst = seq.query(x, y, k)); } else if(opt == 'M') { int x = getInt() ^ lst, w = getInt() ^ lst; seq.modify(x, w); } }}

转载于:https://www.cnblogs.com/ZeonfaiHo/p/7096471.html

你可能感兴趣的文章
IIS负载均衡-Application Request Route详解第六篇:使用失败请求跟踪规则来诊断ARR...
查看>>
管理信息系统 第三部分 作业
查看>>
织梦首页TAG标签页的仿制
查看>>
织梦系统调用点击次数代码优化提高页面打开速度
查看>>
[Leetcode Week13]Search a 2D Matrix
查看>>
通过被调函数改变主调函数的值
查看>>
android 数据存储之SQLite
查看>>
java 对象的序列化与反序列化
查看>>
luogu最长连号
查看>>
二叉树、树、森林
查看>>
查看端口占用cmd命令
查看>>
2019.01.17王苛震作业
查看>>
解决package jdk1.8-2000:1.8.0_171-fcs.x86_64 is already installed问题
查看>>
XPath Helper和XPath语法
查看>>
Halcon学习(八)文本操作
查看>>
MFC电子词典
查看>>
简单工厂(Simple Factory)
查看>>
04: 打开tornado源码剖析处理过程
查看>>
02: 安装epel 解决centos7无法使用yum安装nginx
查看>>
清除浮动
查看>>