1 /*
2 题意:给你n条垂直线段,问有多少组三个线段,两两可见,
3 可见定义为对于两条线段有一条水平线段连接,不经过任意其他线段;
4
5 线段树建图,然后爆力判有几组(不知道效率如何);
6 从左到右扫描,先判断该区间内有可以连接哪几条线段,建图;
7 然后再插入;
8
9 问题:对于[1,4],[1,2],[3,4],[1,4]
10 如果直接1-2,3-4覆盖,当用1-4query的时候,
11 会发现不存在(2,3)区域的标记,
12 解决方法,每个点之间都插入一个点,用偶数表示原先的点,
13 用奇数表示点之间的区域,0,1,2,3,4
14 0 1 2
15
16 */
17 #include<cstdio>
18 #include<cstring>
19 #include<cstdlib>
20 #include<algorithm>
21 #include<iostream>
22 #include<cmath>
23 #include<vector>
24 #define lson l,m,rt<<1
25 #define rson m+1,r,rt<<1|1
26 using namespace std;
27 const int N=8000+10;
28 struct Edge{
29 int l,r,idx;
30 Edge(){}
31 Edge(int a,int b,int c):l(a),r(b),idx(c){}
32 void output(){
33 cout<<l<<" "<<r<<" "<<idx<<endl;
34 }
35 };
36 vector<Edge> g[N];
37 vector<int> mz[N];
38 bool vis[N][N];
39 int n;
40 int col[N<<3];//要扩大
41 void pushdown(int rt){
42 if (col[rt]!=-1){
43 col[rt<<1]=col[rt<<1|1]=col[rt];
44 col[rt]=-1;
45 }
46 }
47 void pushup(int rt){
48 if (col[rt<<1]!=col[rt<<1|1]){
49 col[rt]=-1;
50 }else col[rt]=col[rt<<1];
51 }
52 void update(int L,int R,int v,int l,int r,int rt){
53 if (L<=l && r<=R){
54 col[rt]=v;
55 return;
56 }
57 pushdown(rt);
58 int m=(l+r)>>1;
59 if (L<=m) update(L,R,v,lson);
60 if (m< R) update(L,R,v,rson);
61 pushup(rt);
62
63 }
64 void query(int L,int R,int v,int l,int r,int rt){
65
66 if (L<=l && r<=R && col[rt]!=-1){
67 if (col[rt]==0) return ;
68 if (vis[v][col[rt]]==0){
69 mz[v].push_back(col[rt]);
70 mz[col[rt]].push_back(v);
71 vis[v][col[rt]]=1;
72 vis[col[rt]][v]=1;
73 }
74 return ;
75 }
76 if (l==r) return;
77 pushdown(rt);
78 int m=(l+r)>>1;
79 if (L<=m) query(L,R,v,lson);
80 if (m< R) query(L,R,v,rson);
81 }
82 void work(){
83 memset(col,0,sizeof(col));
84 for (int i=0;i<=n;i++) for (int j=0;j<=n;j++) vis[i][j]=0;
85 for (int i=0;i<N;i++){
86 if (g[i].size()!=0){
87 for (int j=0;j<g[i].size();j++){
88 Edge u=g[i][j];
89 query(u.l*2,u.r*2,u.idx,0,N*2-1,1);
90 }
91 for (int j=0;j<g[i].size();j++){
92 Edge u=g[i][j];
93 update(u.l*2,u.r*2,u.idx,0,N*2-1,1);
94 }
95 }
96 }
97
98 int ret=0;
99 for (int i=1;i<=n;i++){
100 for (int j=0;j<mz[i].size();j++){
101 int c=mz[i][j];
102 for (int k=0;k<mz[c].size();k++){
103 int w=mz[c][k];
104 if (vis[w][i]) ret++;
105 }
106 }
107 }
108 printf("%d\n",ret/6);
109 }
110 void read(){
111 int x,y1,y2;
112 for (int i=0;i<N;i++) {
113 g[i].clear();mz[i].clear();
114 }
115 for (int i=0;i<n;i++){
116 scanf("%d%d%d",&y1,&y2,&x);
117 g[x].push_back(Edge(y1,y2,i+1));
118 }
119 }
120 int main(){
121 int T;scanf("%d",&T);
122 while (T--){
123 scanf("%d",&n);
124 read();
125 work();
126 }
127
128 }
129 /*
130 1
131 5
132 0 4 1
133 1 3 2
134 1 3 3
135 2 4 3
136 0 5 4
137 */