题解 P7424 [THUPC2017] 天天爱射击
本题有很多种做法,这里提供了一种应该是理论时间复杂度最优的
题目描述挺好理解的,问题在于怎么转换题意。
直接顺着题意在线做复杂度肯定是不行的,简单思考后发现把题意转化成求每个木板被哪颗子弹击中即可。
对于第
于是想到一个典型的问题:静态区间第 k 小。
这里的关键字是每颗子弹发射的先后顺序,对于
于是可以用主席树处理这样的问题,时间复杂度即为主席树的
有个重要的内容,每个点上可能有多个子弹,所以每个点开一个 vector
,然后把该点所存的所有子弹顺序编号都放进主席树的这棵分树中,不影响区间查询的正确性。因此主席树的空间也要开大一倍,来处理所有的子弹都在一个点的那种极限数据。
这道题还是挺好想的,思维量不大也很好写。
具体的某些实现可以看看代码。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, LOG = 20, inf = 1e9;
int n, m, t;
int l[N], r[N], s[N], ans[N];
int rt[N], val[N << 1];
int cnt;
vector <int> a[N];
struct President_Tree {
int sum, l, r;
} tree[(N << 1) * LOG];
void build(int &node, int l, int r) {
node = ++cnt;
tree[node].sum = 0;
if(l == r)
return;
int mid = l + r >> 1;
build(tree[node].l, l, mid);
build(tree[node].r, mid + 1, r);
}
void update(int &node, int pre, int l, int r, int x) {
node = ++cnt;
tree[node] = tree[pre];
tree[node].sum = tree[pre].sum + 1;
if(l == r)
return;
int mid = l + r >> 1;
if(x <= mid)
update(tree[node].l, tree[pre].l, l, mid, x);
else
update(tree[node].r, tree[pre].r, mid + 1, r, x);
}
int query(int u, int v, int l, int r, int k) {
int ans, mid = l + r >> 1, x = tree[tree[v].l].sum - tree[tree[u].l].sum;
if(l == r)
return l;
if(x >= k)
ans = query(tree[u].l, tree[v].l, l, mid, k);
else
ans = query(tree[u].r, tree[v].r, mid + 1, r, k - x);
return ans;
}
int main() {
scanf("%d%d", &n, &t);
for(int i = 1; i <= n; i++)
scanf("%d%d%d", &l[i], &r[i], &s[i]);
for(int i = 1; i <= 2e5; i++) {
val[++m] = inf;
a[i].push_back(inf);
}
for(int i = 1; i <= t; i++) {
int x;
scanf("%d", &x);
if(a[x][0] == inf)
val[x] = a[x][0] = i;
else {
val[++m] = i;
a[x].push_back(i);
}
}
sort(val + 1, val + 1 + m);
m = unique(val + 1, val + 1 + m) - val - 1;
build(rt[0], 1, m);
for(int i = 1; i <= 2e5; i++) {
a[i][0] = lower_bound(val + 1, val + 1 + m, a[i][0]) - val;
update(rt[i], rt[i - 1], 1, m, a[i][0]);
for(int j = 1; j < a[i].size(); j++)
update(rt[i], rt[i], 1, m, a[i][j]);
}
for(int i = 1; i <= n; i++) {
int res = query(rt[l[i] - 1], rt[r[i]], 1, m, s[i]);
if(val[res] != inf)
ans[val[res]]++;
}
for(int i = 1; i <= t; i++)
printf("%d\n", ans[i]);
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话