安吉D6-T1
- 1安吉D19 T1
- 2安吉D19 T3
- 3安吉D20 模考12总结
- 4安吉D17 T3
- 5安吉D17 T4
- 6安吉D19 模考11总结
- 7安吉D15 A
- 8安吉D16 T4
- 9安吉D17 T1
- 10安吉D17 模考10总结
- 11安吉D16 T3
- 12安吉D16 模考9总结
- 13安吉D13 模考8总结
- 14安吉D13-T2
- 15安吉D13-T3
- 16安吉D12-T3
- 17安吉D11-B
- 18安吉D11-C
- 19安吉D11-D
- 20安吉D12 模考7总结
- 21安吉D12-T2
- 22安吉D11-A
- 23安吉D10 模考6总结
- 24安吉D10-T3
- 25安吉D10-T4
- 26安吉D8-E
- 27安吉D9-T4
- 28安吉D8-A
- 29安吉D8-B
- 30安吉D8-C
- 31安吉D8-D
- 32安吉D9 模考5总结
- 33安吉D9-T2
- 34安吉D9-T3
- 35安吉D6-T4
- 36安吉D4-G
- 37安吉D5-T2
- 38安吉D6 模考4总结
- 39安吉D6-T1本文
- 40安吉D6-T3
- 41安吉-开营测试 T4
- 42安吉D5 模考3总结
- 43安吉D5-T3
- 44安吉D4-A
- 45安吉D4-B
- 46安吉D4-C
- 47安吉D4:容斥原理
- 48安吉Day4-D
- 49安吉D3 模考2总结
- 50安吉D3-T1
- 51安吉D3-T2
- 52安吉D3-T4
- 53安吉D2 模考1总结
- 54安吉D2-T2
- 55安吉D1-G
- 56安吉D1-L
- 57安吉D2-T4
原题呈现
数组询问
题目描述
有一个由 个整数组成的数组,你需要回答一些关于这个数组的询问.
输入格式
第一行输入两个整数 ,表示数组长度和询问次数.
第二行输入 个整数 ,表示数组中的数字.
接下来 行,每行输入两个整数 ,表示一次询问:
- 如果 ,表示询问数组中 数字的数量.
- 如果 ,表示询问数组中字典序 数字的数量.
- 如果 ,表示询问数组中 ,且字典序也 数字的数量.
其中“字典序比较”指把整数当成十进制字符串比较.例如:
- ,因为字典序先比较首字符,.
- ,因为首位同为 ,第二位 .
- ,如果一个字符串是另一个字符串的真前缀,那么长度更长的字符串字典序更大.
输出格式
对于每次询问输出一行一个整数,表示答案.
样例
输入 #1
8 59 88 777 6666 55555 114514 321 12341 2222 2223 2221 1145142 114514输出 #1
66407数据范围
本题采用捆绑评测,对于一个子任务,你必须通过其中的所有数据才能得到相应分数.
| 子任务编号 | 分数 | 特殊性质 | ||
|---|---|---|---|---|
| 1 | 25 | 无 | ||
| 2 | 10 | 无 | ||
| 3 | 10 | 无 | ||
| 4 | 10 | 无 | ||
| 5 | 10 | 无 | ||
| 6 | 10 | |||
| 7 | 10 | |||
| 8 | 15 | 无 |
全部数据范围
显然,对于操作 1,只要将数组排序,然后使用 lower_bound 进行查询,复杂度 .对于操作 2,只要将数组按字典序排序,然后使用字典序的 lower_bound 进行查询,复杂度 .
重点看操作 3.如果将所有的数字按数学顺序排序,每一个值 得到一个排名 ,再按字典序排序,所有数字又得到一个排名 ,那么,原问题转换为,对于给定值 ,查找所有的 满足 且 .满足条件的所有方案数可以使用容斥,即所有的 个点,减去所有 的点(设为 ),减去所有 的点(设为 ),再加上被重复减去的的 且 的点(设为 ), 可以使用 n 减去操作 1 的结果, 可以使用 n 减去操作 2 的结果,而求解 问题为二维偏序.
具体的,将所有操作中的参数 离线,并将这些参数依照上面的标准获得两个排名 和 (由于 不参与排序,于是这个排名就相当于所有小于 的数的数量 +1),将所有 和 的两个排名视作一个二维平面上的两个坐标,于是所有 和 就可以视作 1 个点.
此时参数 对应询问的答案即为以 为右下角,原点为左上角的矩形内,原始点的数量.将所有点按照横坐标排序(相同则原始点排在查询点之前),这样就省去了一维,只需考虑纵坐标的大小.依照排序顺序从小到大进行遍历,遍历到每一个点:
- 若该点为原始点:将该点的纵坐标加入树状数组.
- 若该点为查询点:查询树状数组中处于 1 和该点纵坐标之间的区间和,该和即为该查询的答案.
标程
#include <bits/stdc++.h>using namespace std;#define int long longconst int N = 3e5 + 100;int n, Q, a[N], b[N], rkv[N], rkd[N], opt[N], x[N], ans[N], lenV, lenD;
// 按字典序排序的结构体struct DictInt { int v, id; friend bool operator<(const DictInt x, const DictInt y) { int vx = x.v, vy = y.v, size1 = 0, size2 = 0; int ka[20], kb[20]; while (vx > 0) { int xx = vx % 10; ka[++size1] = xx; vx /= 10; } while (vy > 0) { int yy = vy % 10; kb[++size2] = yy; vy /= 10; } for (int i = 1; i <= min(size1, size2); i++) { int ptr1 = size1 - i + 1, ptr2 = size2 - i + 1; if (ka[ptr1] < kb[ptr2]) return true; if (ka[ptr1] > kb[ptr2]) return false; } return size1 < size2; }} d[N];
int calLessV(int x) { return upper_bound(b + 1, b + lenV + 1, x) - b - 1; }
int calLessD(int x) { DictInt di; di.v = x; di.id = 0; return upper_bound(d + 1, d + lenD + 1, di) - d - 1;}
// 树状数组struct BIT { int f[N]; int size; BIT() {} void init(int size) { this->size = size; } int lowbit(int x) { return x & (-x); } void upd(int p, int v) { for (int i = p; i <= size; i += lowbit(i)) { f[i] += v; } } int qry(int p) { int ans = 0; for (int i = p; i >= 1; i -= lowbit(i)) { ans += f[i]; } return ans; } int qry(int l, int r) { return qry(r) - qry(l - 1); }} bit;
struct Point { int x, y, qid; friend bool operator<(const Point a, const Point b) { if (a.x == b.x) { if (a.qid == -1 && b.qid == -1) { return a.y < b.y; } if (a.qid == -1) return true; if (b.qid == -1) return false; return a.y < b.y; } return a.x < b.x; }};vector<Point> pt;
signed main() {#ifdef ONLINE_JUDGE freopen("dichrome.in", "r", stdin); freopen("dichrome.out", "w", stdout);#endif ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> Q; for (int i = 1; i <= n; i++) { int x; cin >> x; d[i] = {x, i}; a[i] = x; b[i] = x; } sort(b + 1, b + n + 1); lenV = n; for (int i = 1; i <= n; i++) { rkv[i] = lower_bound(b + 1, b + n + 1, a[i]) - b; } sort(d + 1, d + n + 1); lenD = n; for (int i = 1; i <= n; i++) { DictInt di = {a[i], i}; rkd[i] = lower_bound(d + 1, d + n + 1, di) - d; pt.push_back({rkv[i], rkd[i], -1}); }
for (int i = 1; i <= Q; i++) { int op, xx; cin >> op >> xx; opt[i] = op; x[i] = xx; if (op == 3) { pt.push_back({calLessV(x[i]), calLessD(x[i]), i}); } }
sort(pt.begin(), pt.end());
bit.init(n); for (int i = 0; i < pt.size(); i++) { if (pt[i].qid == -1) { bit.upd(pt[i].y, 1); } else { ans[pt[i].qid] = bit.qry(pt[i].y); } }
for (int i = 1; i <= Q; i++) { if (opt[i] == 1) { ans[i] = n - calLessV(x[i]); } if (opt[i] == 2) { ans[i] = n - calLessD(x[i]); } if (opt[i] == 3) { ans[i] = n - calLessD(x[i]) - calLessV(x[i]) + ans[i]; } cout << ans[i] << endl; } return 0;}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!


