视频加载失败

安吉D6-T1

1521 字
8 分钟
安吉D6-T1
原题呈现

数组询问#

题目描述#

有一个由 nn 个整数组成的数组,你需要回答一些关于这个数组的询问.

输入格式#

第一行输入两个整数 n,Qn, Q,表示数组长度和询问次数.

第二行输入 nn 个整数 a1ana_1 \sim a_n,表示数组中的数字.

接下来 QQ 行,每行输入两个整数 opt,xopt, x,表示一次询问:

  • 如果 opt=1opt=1,表示询问数组中 >x> x 数字的数量.
  • 如果 opt=2opt=2,表示询问数组中字典序 >x> x 数字的数量.
  • 如果 opt=3opt=3,表示询问数组中 >x> x,且字典序也 >x> x 数字的数量.

其中“字典序比较”指把整数当成十进制字符串比较.例如:

  • 123<9123 < 9,因为字典序先比较首字符,1<91 < 9
  • 870>8099870 > 8099,因为首位同为 88,第二位 7>07 > 0
  • 12<12312 < 123,如果一个字符串是另一个字符串的真前缀,那么长度更长的字符串字典序更大.

输出格式#

对于每次询问输出一行一个整数,表示答案.

样例#

输入 #1#

8 5
9 88 777 6666 55555 114514 321 1234
1 222
2 222
3 222
1 114514
2 114514

输出 #1#

6
6
4
0
7

数据范围#

本题采用捆绑评测,对于一个子任务,你必须通过其中的所有数据才能得到相应分数.

子任务编号分数n,Qn, Qai,xa_i, x特殊性质
1255000\le 5000<109< 10^9
210105\le 10^510910^9
3103×105\le 3\times10^5<100< 100
4103×105\le 3\times10^5<106< 10^6
5103×105\le 3\times10^5108\ge 10^8
6103×105\le 3\times10^510910^9opt=1opt=1
7103×105\le 3\times10^510910^9opt=2opt=2
8153×105\le 3\times10^510910^9

全部数据范围#

  • 1n,Q3×1051 \le n, Q \le 3\times10^5
  • 1ai,x<1091 \le a_i, x < 10^9
  • opt{1,2,3}opt \in \{1, 2, 3\}

显然,对于操作 1,只要将数组排序,然后使用 lower_bound 进行查询,复杂度 O(nlogn)O(n\log n).对于操作 2,只要将数组按字典序排序,然后使用字典序的 lower_bound 进行查询,复杂度 O(nlogn)O(n\log n)

重点看操作 3.如果将所有的数字按数学顺序排序,每一个值 aia_i 得到一个排名 rkvai\operatorname{rkv}{a_i},再按字典序排序,所有数字又得到一个排名 rkdai\operatorname{rkd}{a_i},那么,原问题转换为,对于给定值 xx,查找所有的 ii 满足 rkvai>rkvx\operatorname{rkv}{a_i} > \operatorname{rkv}{x}rkdai>rkdx\operatorname{rkd}{a_i} > \operatorname{rkd}{x}.满足条件的所有方案数可以使用容斥,即所有的 nn 个点,减去所有 rkvairkvx\operatorname{rkv}{a_i} \leq \operatorname{rkv}{x} 的点(设为 A1A_1),减去所有 rkdairkdx\operatorname{rkd}{a_i} \leq \operatorname{rkd}{x} 的点(设为 A2A_2),再加上被重复减去的的 rkvairkvx\operatorname{rkv}{a_i} \leq \operatorname{rkv}{x}rkdairkdx\operatorname{rkd}{a_i} \leq \operatorname{rkd}{x} 的点(设为 B12B_{12}),A1A_1 可以使用 n 减去操作 1 的结果,A2A_2 可以使用 n 减去操作 2 的结果,而求解 B12B_{12} 问题为二维偏序.

具体的,将所有操作中的参数 xix_i 离线,并将这些参数依照上面的标准获得两个排名 rkdxi\operatorname{rkd}{x_i}rkvxi\operatorname{rkv}{x_i}(由于 xix_i 不参与排序,于是这个排名就相当于所有小于 xix_i 的数的数量 +1),将所有 aia_ixix_i 的两个排名视作一个二维平面上的两个坐标,于是所有 aia_ixix_i 就可以视作 1 个点.

此时参数 xix_i 对应询问的答案即为以 xix_i 为右下角,原点为左上角的矩形内,原始点的数量.将所有点按照横坐标排序(相同则原始点排在查询点之前),这样就省去了一维,只需考虑纵坐标的大小.依照排序顺序从小到大进行遍历,遍历到每一个点:

  • 若该点为原始点:将该点的纵坐标加入树状数组.
  • 若该点为查询点:查询树状数组中处于 1 和该点纵坐标之间的区间和,该和即为该查询的答案.

标程

#include <bits/stdc++.h>
using namespace std;
#define int long long
const 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;
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

安吉D6-T1
https://blog.jerrylab.top/posts/problem/anji2026/D6/T1/
作者
Jerry
发布于
2026-08-06
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Jerry
Hello, I'm Jerry.
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签
最新动态
站点统计
文章
80
分类
3
标签
35
总字数
89,198
运行时长
0
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.16.5
文章许可
CC BY-NC-SA 4.0