NOIP 2017 Senior 6
来源:互联网 发布:淘宝推广收费标准 编辑:程序博客网 时间:2024/06/05 15:11
传送门(JZOJ)
1.对于 30% 的数据
直接模拟即可
2.对于 50% 的数据(50000,查询少)
发现时间够,但是空间不够,又发现询问次数比较少,因此可以只保存部分行和最后一列。模拟即可。
3.对于 70% 的数据(仅一行)
由于只有一行,我们可以每个人对应一个平衡树结点,然后想一个排序方法。方法就是维护一个优先级,新插入结点的优先级为 n + i,i 指第 i 次查询。套用名次树模板即可,期望时间复杂度 O(n * log n)。
4.对于 100% 的数据
以上做法都不用动脑,100% 的就要考虑下了。参考平衡树做法(让新插入的值的位置为n + i),我们可以考虑用动态开结点的线段树:为每一行的前 m - 1 个人分别开一棵(简称行线段树),再为最后一列单独开一棵(简称列线段树)。但是一开始的初始化怎么做?不可能给每个叶节点赋值吧。这时就要用到线段树的灵活性了。
如果我们难以对每个结点的 size 进行初始化,怎么办?改变 size 的含义!之前 size 表示在 r - l + 1 (这个我们是知道的)中,有多少个叶结点(或者叶结点的和为多少)。现在我们改成 r - l + 1 - 叶结点个数,不就不用初始化了吗?
每个人的编号也是不用初始化的,我们可以算。如果是新加入的人,我们可以保存他的编号。如果这个人的在线段树中的位置大于等于 m(以行线段树为例),我们就可以知道这个人是新加入的,这个人的编号我们是保存了的。如果小于 m,这个人一定不是新加入的,这就意味着它可以算出来!
至此,所有初始化问题已经解决,剩下的问题也就可以不动脑了。
参考代码
#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <string>#include <stack>#include <queue>#include <deque>#include <map>#include <set>#include <bitset>typedef long long INT;using std::cin;using std::cout;using std::endl;inline INT readIn(){ INT a = 0; bool minus = false; char ch = getchar(); while (!(ch == '-' || (ch >= '0' && ch <= '9'))) ch = getchar(); if (ch == '-') { minus = true; ch = getchar(); } while (ch >= '0' && ch <= '9') { a = a * 10 + (ch - '0'); ch = getchar(); } if (minus) a = -a; return a;}inline void printOut(INT x){ char buffer[20]; INT length = 0; bool minus = x < 0; if (minus) x = -x; do { buffer[length++] = x % 10 + '0'; x /= 10; } while (x); if (minus) buffer[length++] = '-'; do { putchar(buffer[--length]); } while (length); putchar('\n');}const INT maxn = INT(3e5) + 5;INT n, m, q;class SegTree{ struct Node { INT size; INT val; Node* lc; Node* rc; Node() : size(), val(), lc(), rc() {} }; static Node pool[6000000]; static Node* cnt; Node* null; Node* root;#define DEF INT mid = (l + r) >> 1#define CNT node, l, r#define LC node->lc, l, mid#define RC node->rc, mid + 1, r#define PARAM Node* &node, INT l, INT r void alloc(Node* &r) { if (r == null) { r = new(cnt++) Node; r->lc = r->rc = null; } } INT findKth(PARAM, INT k, INT& pos) { alloc(node); if (l == r) { node->size = 1; pos = l; return node->val; } DEF; INT s = mid - l + 1; s = s - node->lc->size; INT ret; if (k <= s) ret = findKth(LC, k, pos); else ret = findKth(RC, k - s, pos); node->size = node->lc->size + node->rc->size; return ret; } INT g_Pos, g_Val; void insert(PARAM) { alloc(node); if (l == r) { node->size = 0; node->val = g_Val; return; } DEF; if (g_Pos <= mid) insert(LC); else insert(RC); node->size = node->lc->size + node->rc->size; }public: SegTree() { null = new Node; root = null->lc = null->rc = null; } INT kth(INT k, INT& pos) { return findKth(root, 1, std::max(n, m) + q, k, pos); } void insert(INT pos, INT val) { g_Pos = pos; g_Val = val; insert(root, 1, std::max(n, m) + q); }} trees[maxn], colum;SegTree::Node SegTree::pool[6000000];SegTree::Node* SegTree::cnt = pool;INT size[maxn];void run(){ n = readIn(); m = readIn(); q = readIn(); for (int i = 1; i <= n; i++) size[i] = m - 1; size[n + 1] = n; for (int i = 1; i <= q; i++) { INT x = readIn(); INT y = readIn(); if (y == m) { INT pos; INT ans = colum.kth(x, pos); if (pos <= n) ans = m * pos; colum.insert(++size[n + 1], ans); printOut(ans); } else { INT pos1; INT ans = trees[x].kth(y, pos1); if (pos1 < m) ans = m * (x - 1) + pos1; INT pos2; INT ins = colum.kth(x, pos2); if (pos2 <= n) ins = m * pos2; trees[x].insert(++size[x], ins); colum.insert(++size[n + 1], ans); printOut(ans); } }}int main(){#ifndef LOCAL freopen("phalanx.in", "r", stdin); freopen("phalanx.out", "w", stdout);#endif run(); return 0;}
其实我不建议用内存池,因为结点数不是特别好算(理论上这个可是要 2 * 20 * 300000 的)。考试时不可能卡你的 new,而用 new 就不会出现溢出错误,所以建议用 new 就可以了。(用 new 方法:alloc 中改成 r = new Node;
)
- NOIP 2017 Senior 6
- NOIP 2017 Senior 1
- NOIP 2017 Senior 3
- NOIP 2017 Senior 5
- NOIP 2011 Senior 6
- NOIP 2014 Senior 6
- NOIP 2016 Senior 6
- NOIP 2015 Senior 6
- NOIP 2013 Senior 6
- NOIP 2009 Senior 1
- NOIP 2009 Senior 4
- NOIP 2009 Senior 3
- NOIP 2011 Senior 2
- NOIP 2011 Senior 3
- NOIP 2011 Senior 4
- NOIP 2011 Senior 5
- NOIP 2012 Senior 2
- NOIP 2012 Senior 5
- hdu 1864 最大报销额
- postgresql创建表
- Minor GC、Major GC和Full GC之间的区别
- 【Scikit-Learn 中文文档】优化估计器的超参数
- yii框架学习经历-2.6使用 Gii 生成代码
- NOIP 2017 Senior 6
- 特征点的提取与匹配
- cordova maven太慢,阿里地址
- Unity Mesh合并
- Android 16进制byte数组和16进制String,String之间转换
- uber的配置
- SUSE 11 SP3下搭建PXC(Percona XtraDB Cluster)
- 20 个 CSS 高级技巧汇总
- 如何为Kafka集群选择合适的Topics/Partitions数量