正难则反
既然不好分情况(码长参考WQS
奆
奆
奆佬),那就从总情况中减(主要是因为我菜)
首先,总情况有
C
n
3
C_{n}^{3}
Cn3种(对吧)。然后再考虑不合法的情况(即有
t
o
p
i
c
s
topics
topics或
d
i
f
f
i
c
u
l
t
i
e
s
difficulties
difficulties相同的情况),我们设
t
i
m
e
s
t
i
times_{t_i}
timesti表示
t
i
t_i
ti在
n
n
n个数中出现的次数,
t
i
m
e
s
d
i
times_{d_i}
timesdi表示
d
i
d_i
di在
n
n
n个数中出现的次数。则对于每一个
t
i
t_i
ti和
d
i
d_i
di,关于它重复的次数就等于
(
t
i
m
e
s
t
i
−
1
)
×
(
t
i
m
e
s
d
i
−
1
)
(times_{t_i}-1) \times (times_{d_i}-1)
(timesti−1)×(timesdi−1)
现在我们来解释一下上式,在所有为
t
i
t_i
ti或
d
i
d_i
di的项中(除它自己)随机选一对与它组成一组,一定不行,所以要减一并相乘(乘法原理)。对每一个
i
∈
[
1
,
n
]
i \in [1,n]
i∈[1,n],计算上式并相加即是不合法的情况数。
直接开两个桶记录一下。
清空!!!!!!!
清空!!!!!!!
清空!!!!!!!
#include<bits/stdc++.h>
#define ll long long
#define ldb long double
#define db double
#define mkp make_pair
#define pbk push_back
#define fir first
#define sec second
#define mem(aaa,bbb) memset(aaa,bbb,sizeof aaa)
#define _max(aaa,bbb,ccc) max(aaa,max(bbb,ccc))
#define _min(aaa,bbb,ccc) min(aaa,min(bbb,ccc))
using namespace std;
const ll N=2e5+10;
template <typename T> inline void read(T &x){
x=0;T f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-')f=-1;
for(;isdigit(c);c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x*=f;
}
template<typename T,typename ...Args>void read(T &x,Args&...args){read(x),read(args...);}
template <typename T> void wrt(T x){
if(x<0) x=-x,putchar('-');
if(x>9) wrt(x/10);
putchar(x%10+48);
}
template <typename T> void wrt(T x,char c){wrt(x),putchar(c);}
int T,n,t[N],d[N];
unordered_map<int,int>tt,td;//桶,数组+memset会TLE
ll ans;
int main(){
read(T);
while(T--){
scanf("%d",&n),ans=n*(n-1ll)*(n-2ll)/6ll,tt.clear(),td.clear();
for(int i=1;i<=n;i++)scanf("%d%d",&t[i],&d[i]),tt[t[i]]++,td[d[i]]++;
for(int i=1;i<=n;i++)ans-=1ll*(tt[t[i]]-1)*(td[d[i]]-1);
printf("%lld\n",ans);
}
return 0;
}