# [WC2021] 括号路径
## 题目描述
给定一张 $n$ 个点 $2 m$ 条边的有向图,图中的每条边上都有一个标记,代表一个左括号或者右括号。共有 $k$ 种不同的括号类型,即图中可能有 $2 k$ 种不同的标记。点、边、括号种类均从 $1$ 开始编号。
图中的每条边都会和另一条边成对出现。更具体地,若图中存在一条标有第 $w$ 种括号的左括号的边 $(u, v)$,则图中一定存在一条标有第 $w$ 种括号的右括号的边 $(v, u)$。同样地,图中每条标有右括号的边将对应着一条反方向的标有同类型左括号的边。
现在请你求出,图中共有多少个点对 $(x, y)$($1 \le x < y \le n$)满足:图中存在一条从 $x$ 出发到达 $y$ 的路径,且按经过顺序将路径各条边上的标记拼接得到的字符串是一个合法的括号序列。
## 输入格式
第一行三个整数 $n, m, k$,分别表示图中的点数,边对数和括号类型数。
接下来 $m$ 行,每行三个整数 $u, v, w$,表示一条从 $u$ 到 $v$ 的有向边,其标记为第 $w$ 种括号的左括号;以及一条从 $v$ 到 $u$ 的有向边,其标记为第 $w$ 种括号的右括号。
输入给出的图中,任意两个不同的顶点间可以有多条有向边相连,但图中不存在连向自身的有向边,即 $u \ne v$。
## 输出格式
输出仅一行一个整数,表示满足条件的点对数量。
## 样例 #1
### 样例输入 #1
```
4 5 1
4 3 1
4 1 1
4 2 1
1 3 1
2 1 1
```
### 样例输出 #1
```
3
```
## 样例 #2
### 样例输入 #2
```
6 8 2
6 1 2
3 5 1
1 2 2
5 1 2
3 6 2
4 3 1
6 2 2
3 2 1
```
### 样例输出 #2
```
10
```
## 样例 #3
### 样例输入 #3
```
见附件中的 bracket/bracket3.in
```
### 样例输出 #3
```
见附件中的 bracket/bracket3.ans
```
## 样例 #4
### 样例输入 #4
```
见附件中的 bracket/bracket4.in
```
### 样例输出 #4
```
见附件中的 bracket/bracket4.ans
```
## 提示
**【样例解释 #1】**
符合条件的点对及其对应的路径为:
$(1, 2)$:$1 \to 3 \to 4 \to 1 \to 2$。
$(1, 4)$:$1 \to 3 \to 4$。
$(2, 4)$:$2 \to 1 \to 4$。
**【数据范围】**
对于所有测试点:$1 \le n \le 3 \times {10}^5$,$1 \le m \le 6 \times {10}^5$,$1 \le k, u, v \le n$,$1 \le w \le k$。
每个测试点的具体限制见下表:
#include<bits/stdc++.h>
#define N 300050
#define ll long long
using namespace std;
map<int, int> mp[N];
queue<pair<int, int> > q;
int fa[N];
int get(int x) {
return fa[x] == x? x : (fa[x] = get(fa[x]));
}
void merge(int x, int y) {
x = get(x), y = get(y);
if(x == y) return;
if(mp[x].size() > mp[y].size()) swap(x, y);
for(auto it : mp[x]) {
if(mp[y][it.first]) q.push(make_pair(mp[y][it.first], it.second));
else mp[y][it.first] = it.second;
}
fa[x] = y; mp[x].clear();
}
void solve() {
while(q.size()) {
int x = q.front().first, y = q.front().second; q.pop();
//printf("%d %d\n", x, y);
merge(x, y);
}
}
int n, m, k, gs[N];
int main() {
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; i ++) fa[i] = i;
for(int i = 1; i <= m; i ++) {
int u, v, c;
scanf("%d%d%d", &u, &v, &c), swap(u, v);
if(!mp[u][c]) mp[u][c] = v;
else q.push(make_pair(mp[u][c], v));
}
solve();
for(int i = 1; i <= n; i ++) gs[get(i)] ++;
ll ans = 0;
for(int i = 1; i <= n; i ++) if(get(i) == i) {
ans += 1ll * gs[i] * (gs[i] - 1) / 2;
}
printf("%lld", ans);
return 0;
}