[统计数对] 题解
来源:互联网 发布:网络咨询流程图 编辑:程序博客网 时间:2024/04/28 13:35
A1350. 数对统计 (罗剑桥)时间限制:1.0s 内存限制:256.0MB试题来源 IOI2012中国国家队训练问题描述 你得到了一个由 N 个非负整数构成的序列 A。 你需要回答关于这个序列的 Q 次询问。 每次询问将提供三个整数参数 v,a,b。你需要统计满足以下三个条件的整数 数对(i, j)的数目:1 <= i <= j <= N, a <= j-i+1 <= b, 并且对于任意i <= k <= j的整数k有A[k] >= v。其中A[k]表示序列A的第k项。输入格式 输入的第一行包括两个正整数 N, Q,分别表示序列 A 的项数和询问数。 第二行,N 个非负整数。其中第 i 个整数表示 A[i]。 接下来的 Q 行,每行 3 个整数 v, a, b,依次表示一次询问的三个参数。输出格式 输出 Q 行,每行一个非负整数。第 i 行的非负整数表示第 i 次询问 的答案。样例输入5 35 3 2 7 43 2 32 2 54 1 1样例输出2103数据规模和约定 20%的数据满足,1 <= N <= 1 000, 1 <= Q <= 1 000; 40%的数据满足,1 <= N <= 50 000, 1 <= Q <= 50 000; 60%的数据满足,1 <= N <= 100 000, 1 <= Q <= 100 000; 100%的数据满足,1 <= N <= 300 000, 1 <= Q <= 300 000, 0 <= A[i], v <= 1 000, 1 <= a, b <= 200 000.
乍看此题,以为是个数据结构题。使劲想也没有想出来什么数据结构可以支持这个,最后乱写全挂。
之后 Orz 了 LYP,觉得这真是一道非常非常好的题目,有非常非常多的值得我所学习的地方。
首先,并不用拘泥于数据结构题的想法,去写在线的算法,因为这里没有修改(没有修改 == 离线?)。
所以,很容易想到的就是把 A 序列和询问都按元素为关键字逆序排序,离线解决每一个询问。
这样一来,区间的产生就容易多了:对于每一个询问,所问的为 A[k] >= v,这就意味着比 v 大的是可以保留的。
所以,每次将大的取出,更新区间集合,然后就可以尽快回答当前关键字的询问,因为区间集合中的每一个元素都是满足条件的(不然就是 0 了)。
这样一来,不用去枚举每一个区间,这是降低时间复杂度的关键。
再者,对于一个询问(v, a, b)和一个合法的区间(s, t),易知其有一需要根据 l1 = b - a + 1 和 l2 = t - s + 1 分情况讨论的公式,但是分情况讨论不便于维护。
所以如何转化呢?首先易知,如果对于 i 满足 s <= i <= t, 则生成满足条件数对的个数易知其为 (l - i + 1) * (l - i + 2), l = t - s + 1 。
发现了什么?显然,如果对于 i, j 满足 s <= i <= j <= t, 则生成满足条件数对的个数为 (l - i + 1) * (l - j + 2) - (l - (j + 1) + 1) * (l - (j + 1) + 2), l = t - s + 1 。
证明显然,只需一减即可知。拆开此式,有 l * l + (3 - i * 2) * l + (i - 3) * i + 2 。记此式为 g(l, i) 。
又因为 s <= i <= t, 所以不讨论范围之外的 i 。又易知每次的询问即当前所有(合法)区间的 g(l, a) - g(l, b + 1) 值和。
所以当前的任务为:快速求出 Σ g(l, a), l >= a 。如何做呢?最容易为所想到的是:维护 Σ g(l, 1 .. n), 再得差求得。
观察 g(l, i), 易得所需要维护的为 Σ l * l, Σ l, Σ count,依次乘以 1, (3 - i * 2), (i - 3) * i + 2 即为 g(l, i) 。
想到了什么?树状数组。
每次如果要删除一个区间(合并时应删除原区间),就在该长度 l 的后缀数组中分别减去 l * l, l, 1 即可。添加同。
如何求 g(l, i)? 求出 1 .. i - 1 的区间和,再用一个总和减去即可。
如何回答询问?求出 g(l, a) - g(l, b + 1), 再分别存入每一次询问中即可。
至此,该问题已解决。
Code :
#include <cstdio>#include <cstdlib>#include <cstring>#include <climits>#include <iostream>#include <algorithm>typedef unsigned uint;typedef long long int64;typedef unsigned long long uint64;#define swap(a, b, t) ({t _ = (a); (a) = (b); (b) = _;})#define max(a, b, t) ({t _ = (a), __ = (b); _ > __ ? _ : __;})#define min(a, b, t) ({t _ = (a), __ = (b); _ < __ ? _ : __;})#define maxn 310000#define maxv 1100#define link(e, i, j) (next[++ adj] = e[i], to[e[i] = adj] = j)int n, m, u, v, a, b, adj = 1;int ufs[maxn], x[maxn << 1], y[maxn << 1], size[maxn];int e1[maxv], e2[maxv], next[maxn << 1], to[maxn << 1];int64 s[maxn], s1[maxn], s2[maxn], ans[maxn];int64 t, t1, t2;int find(int x){ return ufs[x] == x ? x : ufs[x] = find(ufs[x]);}void alter(int p, int d){ int64 d1 = d * p, d2 = d1 * p; t += d, t1 += d1, t2 += d2; for (; p <= n; p += p & - p) s[p] += d, s1[p] += d1, s2[p] += d2;}int64 query(int p){ int64 d = 0, d1 = 0, d2 = 0, q = p + 1; for (; p; p &= p - 1) d += s[p], d1 += s1[p], d2 += s2[p]; d = t - d, d1 = t1 - d1, d2 = t2 - d2; return d * (q * (q - 3) + 2) + (3 - (q << 1)) * d1 + d2;}int main(){ freopen("c.in", "r", stdin); freopen("c.out", "w", stdout); scanf("%d%d", & n, & m); for (int i = 1; i <= n; ++ i) { scanf("%d", & v); link(e1, v, i); } for (int i = 1; i <= m; ++ i) { scanf("%d%d%d", & v, & a, & b); link(e2, v, i), x[adj] = a, y[adj] = b; } for (int i = 1000; i >= 0; -- i) { for (int e = e1[i]; e; e = next[e]) { u = to[e], ufs[u] = u, size[u] = 1; if (v = find(u - 1)) ufs[v] = u, size[u] += size[v], alter(size[v], - 1); if (v = find(u + 1)) ufs[v] = u, size[u] += size[v], alter(size[v], - 1); alter(size[u], 1); } for (int e = e2[i]; e; e = next[e]) ans[to[e]] = (query(x[e] - 1) - query(y[e])) >> 1; } for (int i = 1; i <= m; ++ i) printf("%I64d\n", ans[i]); return 0;}
- [统计数对] 题解
- noip2011 统计单词数 T2题解
- 【BZOJ4403】【lucas】【组合数】序列统计 题解
- CCF 201409-1 相邻数对 题解
- 【题解】洛谷1308 统计单词数…
- 【日常学习】【字符串处理】noip2011普及组第2题 统计单词数题解
- 数值统计题解
- wikioi1296营业额统计题解
- 统计数
- MSTC "数独" 题解
- 数石子题解
- 水仙花数题解
- 数的读法-题解
- 数独题解
- 【BZOJ1026】windy数题解
- 组合数 题解
- 删数问题题解
- luogu1112 波浪数 题解
- 字符串移动(字符串为*号和26个字母的任意组合,把*号都移动到最左侧,把字母移到最右侧并保持相对顺序不变),要求时间和空间复杂度最小 .
- 【转】分析PNG图像文件结构(4)
- 线程和进程的联系和区别
- 【ACMICPC Chengdu Online】1004 数论,类Fib
- 浅淡Servlet技术
- [统计数对] 题解
- 生成 一定范围内的随机数
- 找因数,找相同
- android数据存储(shared preferences)
- mmc子系统学习笔记三 mmc子系统知识储备
- 2012天津赛区网络赛第二题---Number(hdu4279)
- 一个字符串转化为整数
- fork() 问题
- 文献关键词共现矩阵python实现