1 条题解
-
0
自动搬运
来自洛谷,原作者为

Suzt_ilymtics
公主与玫瑰,随时待骑士归来 | AFO | SDUer搬运于
2025-08-24 22:29:45,当前版本为作者最后更新于2021-09-03 22:18:12,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
Solution
经典整体二分,挺简单的一道题。
容易想到,我们知道了每个木板在什么时候被击碎就知道哪颗子弹击碎的它。
对于每个木板可以二分这个时刻,同时考虑所有木板就变成了整体二分。
每颗子弹可以看做树状数组的单点修改。
然后对于一个木板就可以看做查询一段区间被多少颗子弹打击。
能击碎的分一组,不能击碎的分一组。
然后这题套上整体二分的模板就做完了。
不断分治下去,到 时直接统计答案即可。
注意一种特殊情况,有的木板有可能自始至终都没有被击碎。
这种情况很好处理,从 开始分治即可,这样自始至终都没有被击碎的木板会被划分到 的位置,这块贡献就不会被统计进去了。
调这种题要时刻注意细节,样例弱的一匹,不行就自己捏几个。
其他的看代码吧,有详细注释。
Code
/* Work by: Suzt_ilymics Problem: 不知名屑题 Knowledge: 垃圾算法 Time: O(能过) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #define LL long long #define orz cout<<"lkp AK IOI!"<<endl using namespace std; const int MAXN = 4e5+5; const int INF = 1e9+7; const int mod = 1e9+7; const int Max = 2e5; struct node { int l, r, k, type, id; }q[MAXN], q1[MAXN], q2[MAXN]; int n, m, tot = 0; int ans[MAXN]; int l[MAXN], r[MAXN], v[MAXN]; int read(){ int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s; } namespace BIT { int sum[MAXN]; int lb(int x) { return x & -x; } void Modify(int x, int k) { for( ; x <= Max; x += lb(x)) sum[x] += k; } int Query(int x) { int res = 0; for( ; x; x -= lb(x)) res += sum[x]; return res; } } void Solve(int l, int r, int ql, int qr) { // 整体二分 if(ql > qr) return ; // 这种空集直接返回即可。 if(l == r) { for(int i = ql; i <= qr; ++i) if(q[i].type) ans[l]++; // 统计第 l 颗子弹击碎了几个木板。 return ; } int mid = (l + r) >> 1, cnt1 = 0, cnt2 = 0; for(int i = ql; i <= qr; ++i) { if(q[i].type) { int sum = BIT::Query(q[i].r) - BIT::Query(q[i].l - 1); // 树状数组区间求和,表示 [l,mid] 区间的子弹打中了它几次。 if(sum >= q[i].k) { // 打碎了分一组 q1[++cnt1] = q[i]; } else { // 没打碎另分一组。 q[i].k -= sum; // 注意要把这次的贡献算上,以后就不用考虑了。 q2[++cnt2] = q[i]; } } else { if(q[i].id <= mid) { BIT::Modify(q[i].l, 1); q1[++cnt1] = q[i]; } else { q2[++cnt2] = q[i]; } } } for(int i = 1; i <= cnt1; ++i) if(!q1[i].type) BIT::Modify(q1[i].l, -1); // 清空树状数组。 for(int i = 1; i <= cnt1; ++i) q[ql + i - 1] = q1[i]; for(int i = 1; i <= cnt2; ++i) q[ql + cnt1 + i - 1] = q2[i]; Solve(l, mid, ql, ql + cnt1 - 1); Solve(mid + 1, r, ql + cnt1, ql + cnt1 + cnt2 - 1); } int main() { n = read(), m = read(); for(int i = 1; i <= n; ++i) l[i] = read(), r[i] = read(), v[i] = read(); // 注意因为我们子弹和木板共用一个数组 q,要先操作子弹,所以把木板放子弹的后边。 for(int i = 1, x; i <= m; ++i) { x = read(); q[++tot] = (node){x, 0, 0, 0, i}; } for(int i = 1; i <= n; ++i) q[++tot] = (node){l[i], r[i], v[i], 1, i}; Solve(1, m + 1, 1, tot); for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]); return 0; }
- 1
信息
- ID
- 6545
- 时间
- 1000ms
- 内存
- 500MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者