CF283E Cow Tennis Tournament 题解
题目要我们求三元组的数量。根据经验,我们处理一下。发现不合法的三元组只有一种情况:即一个三元组中,一个点的出度为 $2$。记 $d_i$ 为一个点的出度,所以总的答案是 $\binom{3}{n} - \sum \binom{2}{d_i}$。问题转化为如何快速求出每个点的 $d_i$。观察发现,对于一个点,只有经过它的区间才会对它的 $d_i$ 产生影响,显然我们可以利用差分的思想,在每个操作的两个端点进行修改。具体的,把一个 $l \sim r$ 的修改在 $l$ 和 $r + 1$ 分别进行一次区间翻转,我们从小到大按枚举每个点,统计答案。
再说一个代码实现的细节,我们记一个标记 $cs$ 表示当前这个点以前区间翻转操作次数,当 $cs$ 为奇数次时,说明当前这个点被覆盖了,否则覆盖相互抵消或者没被覆盖。
#include<bits/stdc++.h> using namespace std; #define lc k << 1 #define rc lc | 1 #define lcon lc, l, mid #define rcon rc, mid + 1, r #define Mid int mid = l + r >> 1 typedef long long ll; const int N = 1e5 + 500; int n, k; int sum[N << 2], tag[N << 2], len[N << 2], cs; void dk(int k) {tag[k] ^= 1, sum[k] = len[k] - sum[k];} void pd(int k) {if(tag[k]) dk(lc), dk(rc), tag[k] = 0;} void build(int k ,int l, int r) { len[k] = r - l + 1; if(l == r) return; Mid; build(lcon), build(rcon); } void modify(int k, int l, int r, int x, int y) { if(y < l || x > r) return ;if(x <= l && r <= y) return (void)dk(k); pd(k); Mid; if(x <= mid) modify(lcon, x, y); if(y > mid) modify(rcon, x, y); sum[k] = sum[lc] + sum[rc]; } int s[N]; vector<int> L[N]; vector<int> R[N]; int main() { scanf("%d %d", &n, &k); for(int i = 1; i <= n; i++) scanf("%d", s + i); sort(s + 1, s + n + 1); while(k--) { int x, y; scanf("%d %d", &x, &y); x = lower_bound(s + 1, s + n + 1, x) - s; y = upper_bound(s + 1, s + n + 1, y) - s - 1; R[x].push_back(y), L[y + 1].push_back(x); } build(1, 1, n); ll ans = (ll) n * (n - 1) * (n - 2) / 6; for(int i = 1;i <= n; ++i) { for(auto P : L[i]) modify(1, 1, n, P, i - 1), cs ^= 1; for(auto P : R[i]) modify(1, 1, n, i, P), cs ^= 1; int t = sum[1] - cs; ans -= (ll) t * (t - 1) / 2; modify(1, 1, n, i, i); } printf("%lld" ,ans); return 0; }
本文作者:Saka_Noa
本文链接:https://www.cnblogs.com/Saka-Noa/p/17808434.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步