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 中国大陆许可协议进行许可。

posted @   Saka_Noa  阅读(7)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开