#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define se second
#define fi first
#define pii pair<int,int>
#define lowbit(x) x&(-x)
typedef long long ll;
int lson(int p) {return p * 2;}
int rson(int p) {return p * 2 + 1;}
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const long long int inf = 1e17 + 10;

struct node{
    int p[3];
}a[maxn];
struct B{
    int b[3];
    int now;
}belong[maxn];

int ans[maxn],vis[maxn];
int cnt[maxn];
int main()
{
    int n;scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        belong[i].now = 0;
    }
    for(int i = 1;i <= n - 2; i++)
    {
        scanf("%d%d%d",&a[i].p[0],&a[i].p[1],&a[i].p[2]);

        cnt[a[i].p[0] ]++;
        cnt[a[i].p[1] ]++;
        cnt[a[i].p[2] ]++;
        belong[a[i].p[0] ].b[belong[a[i].p[0] ].now++] = i;
        belong[a[i].p[1] ].b[belong[a[i].p[1] ].now++] = i;
        belong[a[i].p[2] ].b[belong[a[i].p[2] ].now++] = i;
    }
    int be = 0,vv = 0,tot = 0,en = 0;
    for(int i = 1; i <= n; i++)
    {
        if(cnt[i] == 1 && be == 0)
        {
            be = belong[i].b[0];
            ans[++tot] = i;
        }
        else if(cnt[i] == 1 && vv == 0 && be != 0)
        {
            vv = i;
            en = belong[i].b[0];
            break;
        }
    }
    ans[n] = vv;
    for(int i = 0; i < 3; i++)
    {
        if(cnt[a[en].p[i]] == 2)
        {
            ans[n - 1] = a[en].p[i];
        }
        else if(cnt[a[en].p[i]] == 3)
        {
            ans[n - 2] = a[en].p[i];
        }
    }
    bool flag = 0;
    vis[be] = 1;
   // printf("vv = %d\n",vv);
    while(1)
    {
        //printf("be = %d\n",be);
        //cout<<tot<<endl;
        if(be == en) break;
        if(tot >= n - 3) break;
        for(int i = 0; i < 3; i++)
        {
            //printf("pi = %d\n",a[be].p[i]);
            if(a[be].p[i] == vv) flag = 1;
        }
        if(flag) break;
        for(int i = 0; i < 3; i++) cnt[a[be].p[i]]--;
        for(int i = 0; i < 3; i++)
        {
            if(cnt[a[be].p[i]] == 1)
            {
                ans[++tot] = a[be].p[i];
                for(int j = 0; j < belong[a[be].p[i]].now; j++)
                {
                    //printf("check %d\n",belong[a[be].p[i]].b[j]);
                    if(!vis[belong[a[be].p[i]].b[j]])
                    {
                        be = belong[a[be].p[i]].b[j];
                        vis[be] = 1;
                        break;
                    }
                }
                break;
            }
        }
    }
    for(int i = 1; i <= n; i++)
    {
        printf("%d ",ans[i]);
    }
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define se second
#define fi first
#define pii pair<int,int>
#define lowbit(x) x&(-x)
typedef long long ll;
int lson(int p) {return p * 2;}
int rson(int p) {return p * 2 + 1;}
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const long long int inf = 1e17 + 10;

struct node{
    int p[3];
}a[maxn];
struct B{
    int b[3];
    int now;
}belong[maxn];

int ans[maxn],vis[maxn];
int cnt[maxn];
int main()
{
    int n;scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        belong[i].now = 0;
    }
    for(int i = 1;i <= n - 2; i++)
    {
        scanf("%d%d%d",&a[i].p[0],&a[i].p[1],&a[i].p[2]);

        cnt[a[i].p[0] ]++;
        cnt[a[i].p[1] ]++;
        cnt[a[i].p[2] ]++;
        belong[a[i].p[0] ].b[belong[a[i].p[0] ].now++] = i;
        belong[a[i].p[1] ].b[belong[a[i].p[1] ].now++] = i;
        belong[a[i].p[2] ].b[belong[a[i].p[2] ].now++] = i;
    }
    if(n == 3)
    {
        printf("%d %d %d\n",a[1].p[0],a[1].p[1],a[1].p[2]);
        return 0;
    }
    if(n == 4)
    {
        int be = 0,vv = 0,tot = 0,en = 0;
        for(int i = 1; i <= n; i++)
        {
            if(cnt[i] == 1 && be == 0)
            {
                be = i;vis[i] = 1;
            }
            else if(cnt[i] == 1 && vv == 0)
            {
                vv = i;vis[i] = 1;
            }
        }
        printf("%d ",be);
        for(int i = 1; i <= n; i++)
        {
            if(!vis[i]) printf("%d ",i);
        }
        printf("%d",vv);
        return 0;
    }
    int be = 0,vv = 0,tot = 0,en = 0;
    for(int i = 1; i <= n; i++)
    {
        if(cnt[i] == 1 && be == 0)
        {
            be = belong[i].b[0];
            ans[++tot] = i;
        }
        else if(cnt[i] == 1 && vv == 0)
        {
            vv = i;
            en = belong[i].b[0];
        }
    }
    ans[n] = vv;
    for(int i = 0; i < 3; i++)
    {
        if(cnt[a[en].p[i]] == 2)
        {
            ans[n - 1] = a[en].p[i];
        }
        else if(cnt[a[en].p[i]] == 3)
        {
            ans[n - 2] = a[en].p[i];
        }
    }
    bool flag = 0;
   // printf("vv = %d\n",vv);
    while(1)
    {
        //printf("be = %d\n",be);
        //cout<<tot<<endl;
        if(tot == n - 3) break;
        vis[be] = 1;
        for(int i = 0; i < 3; i++)
        {
            //printf("pi = %d\n",a[be].p[i]);
            if(a[be].p[i] == vv) flag = 1;
        }
        if(flag) break;
        for(int i = 0; i < 3; i++)
        {
            cnt[a[be].p[i]]--;
            if(cnt[a[be].p[i]] == 1)
            {
                ans[++tot] = a[be].p[i];
                for(int j = 0; j < belong[a[be].p[i]].now; j++)
                {
                    //printf("check %d\n",belong[a[be].p[i]].b[j]);
                    if(!vis[belong[a[be].p[i]].b[j]])
                    {
                        be = belong[a[be].p[i]].b[j];
                        break;
                    }
                }
                //break;
            }
        }
    }
    for(int i = 1; i <= n; i++)
    {
        printf("%d ",ans[i]);
    }
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define se second
#define fi first
#define pii pair<int,int>
#define lowbit(x) x&(-x)
typedef long long ll;
int lson(int p) {return p * 2;}
int rson(int p) {return p * 2 + 1;}
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const long long int inf = 1e17 + 10;

struct node{
    int p[3];
}a[maxn];
struct B{
    int b[3];
    int now;
}belong[maxn];

int ans[maxn],vis[maxn];
int cnt[maxn];
int main()
{
    int n;scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        belong[i].now = 0;
    }
    for(int i = 1;i <= n - 2; i++)
    {
        scanf("%d%d%d",&a[i].p[0],&a[i].p[1],&a[i].p[2]);

        cnt[a[i].p[0] ]++;
        cnt[a[i].p[1] ]++;
        cnt[a[i].p[2] ]++;
        belong[a[i].p[0] ].b[belong[a[i].p[0] ].now++] = i;
        belong[a[i].p[1] ].b[belong[a[i].p[1] ].now++] = i;
        belong[a[i].p[2] ].b[belong[a[i].p[2] ].now++] = i;
    }
    if(n == 3)
    {
        printf("%d %d %d\n",a[1].p[0],a[1].p[1],a[1].p[2]);
        return 0;
    }
    if(n == 4)
    {
        int be = 0,vv = 0,tot = 0,en = 0;
        for(int i = 1; i <= n; i++)
        {
            if(cnt[i] == 1 && be == 0)
            {
                be = i;vis[i] = 1;
            }
            else if(cnt[i] == 1 && vv == 0)
            {
                vv = i;vis[i] = 1;
            }
        }
        printf("%d ",be);
        for(int i = 1; i <= n; i++)
        {
            if(!vis[i]) printf("%d ",i);
        }
        printf("%d",vv);
        return 0;
    }
    int be = 0,vv = 0,tot = 0,en = 0;
    for(int i = 1; i <= n; i++)
    {
        if(cnt[i] == 1 && be == 0)
        {
            be = belong[i].b[0];
            ans[++tot] = i;
        }
        else if(cnt[i] == 1 && vv == 0)
        {
            vv = i;
            en = belong[i].b[0];
        }
    }
    ans[n] = vv;
    for(int i = 0; i < 3; i++)
    {
        if(cnt[a[en].p[i]] == 2)
        {
            ans[n - 1] = a[en].p[i];
        }
        else if(cnt[a[en].p[i]] == 3)
        {
            ans[n - 2] = a[en].p[i];
        }
    }
    bool flag = 0;
   // printf("vv = %d\n",vv);
    while(1)
    {
        //printf("be = %d\n",be);
        //cout<<tot<<endl;
        if(tot == n - 3) break;
        vis[be] = 1;
        for(int i = 0; i < 3; i++)
        {
            //printf("pi = %d\n",a[be].p[i]);
            if(a[be].p[i] == vv) flag = 1;
        }
        if(flag) break;
        for(int i = 0; i < 3; i++)
        {
            cnt[a[be].p[i]]--;
            if(cnt[a[be].p[i]] == 1)
            {
                ans[++tot] = a[be].p[i];
                for(int j = 0; j < belong[a[be].p[i]].now; j++)
                {
                    //printf("check %d\n",belong[a[be].p[i]].b[j]);
                    if(!vis[belong[a[be].p[i]].b[j]])
                    {
                        be = belong[a[be].p[i]].b[j];
                        break;
                    }
                }
                break;
            }
        }
    }
    for(int i = 1; i <= n; i++)
    {
        printf("%d ",ans[i]);
    }
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define se second
#define fi first
#define pii pair<int,int>
#define lowbit(x) x&(-x)
typedef long long ll;
int lson(int p) {return p * 2;}
int rson(int p) {return p * 2 + 1;}
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const long long int inf = 1e17 + 10;

struct node{
    int p[3];
}a[maxn];
struct B{
    int b[3];
    int now;
}belong[maxn];

int ans[maxn],vis[maxn];
int cnt[maxn];
int main()
{
    int n;scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        belong[i].now = 0;
    }
    for(int i = 1;i <= n - 2; i++)
    {
        scanf("%d%d%d",&a[i].p[0],&a[i].p[1],&a[i].p[2]);

        cnt[a[i].p[0] ]++;
        cnt[a[i].p[1] ]++;
        cnt[a[i].p[2] ]++;
        belong[a[i].p[0] ].b[belong[a[i].p[0] ].now++] = i;
        belong[a[i].p[1] ].b[belong[a[i].p[1] ].now++] = i;
        belong[a[i].p[2] ].b[belong[a[i].p[2] ].now++] = i;
    }
    int be = 0,vv = 0,tot = 0,en = 0;
    for(int i = 1; i <= n; i++)
    {
        if(cnt[i] == 1 && be == 0)
        {
            be = belong[i].b[0];
            ans[++tot] = i;
        }
        else if(cnt[i] == 1 && vv == 0)
        {
            vv = i;
            en = belong[i].b[0];
        }
    }
    ans[n] = vv;
    for(int i = 0; i < 3; i++)
    {
        if(cnt[a[en].p[i]] == 2)
        {
            ans[n - 1] = a[en].p[i];
        }
        else if(cnt[a[en].p[i]] == 3)
        {
            ans[n - 2] = a[en].p[i];
        }
    }
    bool flag = 0;
   // printf("vv = %d\n",vv);
    while(1)
    {
        //printf("be = %d\n",be);
        //cout<<tot<<endl;
        if(be == en) break;
        if(tot >= n - 3) break;
        vis[be] = 1;
        for(int i = 0; i < belong[a[be].p[i]].now; i++)
        {
            //printf("pi = %d\n",a[be].p[i]);
            if(a[be].p[i] == vv) flag = 1;
        }
        if(flag) break;
        for(int i = 0; i < 3; i++)
        {
            cnt[a[be].p[i]]--;
            if(cnt[a[be].p[i]] == 1)
            {
                ans[++tot] = a[be].p[i];
                for(int j = 0; j < belong[a[be].p[i]].now; j++)
                {
                    //printf("check %d\n",belong[a[be].p[i]].b[j]);
                    if(!vis[belong[a[be].p[i]].b[j]])
                    {
                        be = belong[a[be].p[i]].b[j];
                        break;
                    }
                }
                break;
            }
        }
    }
    for(int i = 1; i <= n; i++)
    {
        printf("%d ",ans[i]);
    }
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define se second
#define fi first
#define pii pair<int,int>
#define lowbit(x) x&(-x)
typedef long long ll;
int lson(int p) {return p * 2;}
int rson(int p) {return p * 2 + 1;}
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const long long int inf = 1e17 + 10;

struct node{
    int p[3];
}a[maxn];
struct B{
    int b[3];
    int now;
}belong[maxn];

int ans[maxn],vis[maxn];
int cnt[maxn];
int main()
{
    int n;scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        belong[i].now = 0;
    }
    for(int i = 1;i <= n - 2; i++)
    {
        scanf("%d%d%d",&a[i].p[0],&a[i].p[1],&a[i].p[2]);

        cnt[a[i].p[0] ]++;
        cnt[a[i].p[1] ]++;
        cnt[a[i].p[2] ]++;
        belong[a[i].p[0] ].b[belong[a[i].p[0] ].now++] = i;
        belong[a[i].p[1] ].b[belong[a[i].p[1] ].now++] = i;
        belong[a[i].p[2] ].b[belong[a[i].p[2] ].now++] = i;
    }
    int be = 0,vv = 0,tot = 0,en = 0;
    for(int i = 1; i <= n; i++)
    {
        if(cnt[i] == 1 && be == 0)
        {
            be = belong[i].b[0];
            ans[++tot] = i;
        }
        else if(cnt[i] == 1 && vv == 0)
        {
            vv = i;
            en = belong[i].b[0];
        }
    }
    ans[n] = vv;
    for(int i = 0; i < 3; i++)
    {
        if(cnt[a[en].p[i]] == 2)
        {
            ans[n - 1] = a[en].p[i];
        }
        else if(cnt[a[en].p[i]] == 3)
        {
            ans[n - 2] = a[en].p[i];
        }
    }
    bool flag = 0;
   // printf("vv = %d\n",vv);
    while(1)
    {
        //printf("be = %d\n",be);
        //cout<<tot<<endl;
        if(tot >= n - 3) break;
        vis[be] = 1;
        for(int i = 0; i < belong[a[be].p[i]].now; i++)
        {
            //printf("pi = %d\n",a[be].p[i]);
            if(a[be].p[i] == vv) flag = 1;
        }
        if(flag) break;
        for(int i = 0; i < 3; i++)
        {
            cnt[a[be].p[i]]--;
            if(cnt[a[be].p[i]] == 1)
            {
                ans[++tot] = a[be].p[i];
                for(int j = 0; j < belong[a[be].p[i]].now; j++)
                {
                    //printf("check %d\n",belong[a[be].p[i]].b[j]);
                    if(!vis[belong[a[be].p[i]].b[j]])
                    {
                        be = belong[a[be].p[i]].b[j];
                        break;
                    }
                }
                break;
            }
        }
    }
    for(int i = 1; i <= n; i++)
    {
        printf("%d ",ans[i]);
    }
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define se second
#define fi first
#define pii pair<int,int>
#define lowbit(x) x&(-x)
typedef long long ll;
int lson(int p) {return p * 2;}
int rson(int p) {return p * 2 + 1;}
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const long long int inf = 1e17 + 10;

struct node{
    int p[3];
}a[maxn];
struct B{
    int b[3];
    int now;
}belong[maxn];

int ans[maxn],vis[maxn];
int cnt[maxn];
int main()
{
    int n;scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        belong[i].now = 0;
    }
    for(int i = 1;i <= n - 2; i++)
    {
        scanf("%d%d%d",&a[i].p[0],&a[i].p[1],&a[i].p[2]);

        cnt[a[i].p[0] ]++;
        cnt[a[i].p[1] ]++;
        cnt[a[i].p[2] ]++;
        belong[a[i].p[0] ].b[belong[a[i].p[0] ].now++] = i;
        belong[a[i].p[1] ].b[belong[a[i].p[1] ].now++] = i;
        belong[a[i].p[2] ].b[belong[a[i].p[2] ].now++] = i;
    }
    if(n == 3)
    {
        printf("%d %d %d\n",a[1].p[0],a[1].p[1],a[1].p[2]);
        return 0;
    }
    if(n == 4)
    {
        int be = 0,vv = 0,tot = 0,en = 0;
        for(int i = 1; i <= n; i++)
        {
            if(cnt[i] == 1 && be == 0)
            {
                be = i;vis[i] = 1;
            }
            else if(cnt[i] == 1 && vv == 0)
            {
                vv = i;vis[i] = 1;
            }
        }
        printf("%d ",be);
        for(int i = 1; i <= n; i++)
        {
            if(!vis[i]) printf("%d ",i);
        }
        printf("%d",vv);
        return 0;
    }
    int be = 0,vv = 0,tot = 0,en = 0;
    for(int i = 1; i <= n; i++)
    {
        if(cnt[i] == 1 && be == 0)
        {
            be = belong[i].b[0];
            ans[++tot] = i;
        }
        else if(cnt[i] == 1 && vv == 0)
        {
            vv = i;
            en = belong[i].b[0];
        }
    }
    ans[n] = vv;
    for(int i = 0; i < 3; i++)
    {
        if(cnt[a[en].p[i]] == 2)
        {
            ans[n - 1] = a[en].p[i];
        }
        else if(cnt[a[en].p[i]] == 3)
        {
            ans[n - 2] = a[en].p[i];
        }
    }
    bool flag = 0;
   // printf("vv = %d\n",vv);
    while(1)
    {
        //printf("be = %d\n",be);
        //cout<<tot<<endl;
        if(tot == n - 2) break;
        vis[be] = 1;
        for(int i = 0; i < 3; i++)
        {
            //printf("pi = %d\n",a[be].p[i]);
            if(a[be].p[i] == vv) flag = 1;
        }
        if(flag) break;
        for(int i = 0; i < 3; i++)
        {
            cnt[a[be].p[i]]--;
            if(cnt[a[be].p[i]] == 1)
            {
                ans[++tot] = a[be].p[i];
                for(int j = 0; j < belong[a[be].p[i]].now; j++)
                {
                    //printf("check %d\n",belong[a[be].p[i]].b[j]);
                    if(!vis[belong[a[be].p[i]].b[j]])
                    {
                        be = belong[a[be].p[i]].b[j];
                        break;
                    }
                }
                break;
            }
        }
    }
    for(int i = 1; i <= n; i++)
    {
        printf("%d ",ans[i]);
    }
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define io ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
#define ll long long
#define pb push_back
#define pii pair<pair<int,int>,pair<int,int>>
#define f first
#define s second
#define md 1000000007

//=
//%
//_
int main(){
    io;
    int n,a,b,c;
    unordered_map<int,int> mp;
    cin>>n;
    vector<int> v[400001];
    for(int i=1;i<=n-2;i++){
        cin>>a>>b>>c;
        v[a].pb(b); v[a].pb(c);
        v[b].pb(a); v[b].pb(c);
        v[c].pb(a); v[c].pb(b);
        mp[a]++; mp[b]++; mp[c]++;
    }
    int f,s;
    for(int i=1;i<=n;i++){
        if(mp[i]==1){
          f=i; break;
        }
    }
    vector<int> z=v[f];
    if(mp[z[0]]<mp[z[1]]) s=z[0];
    else s=z[1];
    cout<<f<<" "<<s<<" ";
    unordered_map<int,int> visited;
    visited[f]=1; visited[s]=1;
    for(int j=1;j<=n-2;j++){
        vector<int> x=v[f];
        int t;
        for(int i=0;i<x.size();i++){
            if(visited.count(x[i])==0){
                cout<<x[i]<<" ";
                visited[x[i]]=1;
                t=x[i];
                break;
            }
        }
        f=s;
        s=t;
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define io ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
#define ll long long
#define pb push_back
int main(){
    io;
    int n,a,b,c;
    unordered_map<int,int> mp;
    cin>>n;
    vector<vector<int>> v;
    for(int i=1;i<=n-2;i++){
        cin>>a>>b>>c;
        vector<int> x;
        x.pb(a); x.pb(b); x.pb(c);
        v.pb(x);
        mp[a]++; mp[b]++; mp[c]++;
    }
    int f,s;
    for(int i=1;i<=n;i++){
        if(mp[i]==1){
          f=i; break;
        }
    }
    for(int i=0;i<v.size();i++){
        vector<int> x=v[i];
        if(x[0]==f){
            if(mp[x[1]]<mp[x[2]]) s=x[1];
            else s=x[2];
        }
        else if(x[1]==f){
            if(mp[x[0]]<mp[x[2]]) s=x[0];
            else s=x[2];
        }
        else{
            if(mp[x[0]]<mp[x[1]]) s=x[0];
            else s=x[1];
        }
    }
    cout<<f<<" "<<s<<" ";
    unordered_map<int,int> visited;
    visited[f]=1; visited[s]=1;
    for(int j=1;j<=n-2;j++){
        for(int i=0;i<v.size();i++){
            vector<int> x=v[i];
            if((x[0]==f||x[0]==s)&&(x[1]==f||x[1]==s)&&visited.count(x[2])==0){
                cout<<x[2]<<" ";
                f=s; s=x[2];
                visited[x[2]]=1;
            }
            else if((x[0]==f||x[0]==s)&&(x[2]==f||x[2]==s)&&visited.count(x[1])==0){
                cout<<x[1]<<" ";
                f=s; s=x[1];
                visited[x[1]]=1;
            }
            else if((x[1]==f||x[1]==s)&&(x[2]==f||x[2]==s)&&visited.count(x[0])==0){
                cout<<x[0]<<" ";
                f=s; s=x[0];
                visited[x[0]]=1;
            }
        }
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define io ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
#define ll long long
#define pb push_back
#define pii pair<pair<int,int>,pair<int,int>>
#define f first
#define s second
#define md 1000000007

//=
//%
//_
int main(){
    io;
    int n,a,b,c;
    unordered_map<int,int> mp;
    cin>>n;
    vector<int> v[100000];
    for(int i=1;i<=n-2;i++){
        cin>>a>>b>>c;
        v[a].pb(b); v[a].pb(c);
        v[b].pb(a); v[b].pb(c);
        v[c].pb(a); v[c].pb(b);
        mp[a]++; mp[b]++; mp[c]++;
    }
    int f,s;
    for(int i=1;i<=n;i++){
        if(mp[i]==1){
          f=i; break;
        }
    }
    vector<int> z=v[f];
    if(mp[z[0]]<mp[z[1]]) s=z[0];
    else s=z[1];
    cout<<f<<" "<<s<<" ";
    unordered_map<int,int> visited;
    visited[f]=1; visited[s]=1;
    for(int j=1;j<=n-2;j++){
        vector<int> x=v[f];
        int t;
        for(int i=0;i<x.size();i++){
            if(visited.count(x[i])==0){
                cout<<x[i]<<" ";
                visited[x[i]]=1;
                t=x[i];
                break;
            }
        }
        f=s;
        s=t;
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define io ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
#define ll long long
#define pb push_back
#define pii pair<pair<int,int>,pair<int,int>>
#define f first
#define s second
#define md 1000000007

//=
//%
//_
int main(){
    io;
    int n,a,b,c;
    unordered_map<int,int> mp;
    cin>>n;
    vector<int> v[100000];
    for(int i=1;i<=n-2;i++){
        cin>>a>>b>>c;
        v[a].pb(b); v[a].pb(c);
        v[b].pb(a); v[b].pb(c);
        v[c].pb(a); v[c].pb(b);
        mp[a]++; mp[b]++; mp[c]++;
    }
    int f,s;
    for(int i=1;i<=n;i++){
        if(mp[i]==1){
          f=i; break;
        }
    }
    vector<int> z=v[f];
    if(mp[z[0]]<mp[z[1]]) s=z[0];
    else s=z[1];
    cout<<f<<" "<<s<<" ";
    unordered_map<int,int> visited;
    visited[f]=1; visited[s]=1;
    for(int j=1;j<=n-2;j++){
        vector<int> x=v[f];
        for(int i=0;i<x.size();i++){
            if(visited.count(x[i])==0){
                cout<<x[i]<<" ";
                visited[x[i]]=1;
                s=x[i];
                break;
            }
        }
        f=s;
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std ;

#define ll long long
#define pb push_back
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define memf(a) memset(a,false,sizeof(a))
#define all(v) v.begin(),v.end()
#define sz(a) (ll)a.size()
#define F first
#define S second
#define INF 2000000000000000000
#define endl "\n"
#define _time_ 1.0 * clock() / CLOCKS_PER_SEC
#define popcount(x) __builtin_popcountll(x)
#define pll pair<ll,ll>
#define ld long double

const int M=1000000007;
const int MM=998244353;
const long double PI = acos(-1);

ll power(ll b,ll e,ll m)
{
    if(e==0) return 1;
    if(e&1) return b*power(b*b%m,e/2,m)%m;
    return power(b*b%m,e/2,m);
}
ll power( ll b, ll e)
{
    if(e==0) return 1;
    if(e&1) return b*power(b*b,e/2);
    return power(b*b,e/2);
}
template<typename T, typename U> static inline void amin(T &x, U y){ if(y<x) x=y; }
template<typename T, typename U> static inline void amax(T &x, U y){ if(x<y) x=y; }
template<typename T, typename U> ostream& operator<<(ostream &os, const pair<T, U> &p)
{
    return os<<'('<<p.F<< ","<<p.S<<')';
}
#define pii pair<int,int>
const int N=200005;
int n,m,k;

vector<pii> v[N],g[N];

map<pii,map<pii,bool>> mp;
map<pii,bool> check;

int go(int pos,vector<int> kx)
{
    //cout<<pos<<"\n";
    if(pos==k+1)
        return 1;
    int ans=0;
    vector<int> t=kx;
    if(pos==1)
    {
        t[1]=1;
        return go(pos+1,t);
    }
    for(int j=1;j<=pos;++j)
    {
        if(check[{pos,j}])
            continue;
        bool f=false;
        for(int kk=1;kk<pos;++kk)
        {
            if(mp[{pos,j}][{kk,kx[kk]}])
                f=true;
        }
        if(!f)
        {
            t[pos]=j;
            ans+=go(pos+1,t);
        }
    }
    //cout<<pos<<" ";
    //cout<<ans<<"\n";
    return ans;
}

int _runtimeTerror_()
{
    cin>>n>>m>>k;
    if(k==1)
    {
        cout<<0<<"\n";return 0;
    }
    for(int i=0;i<m;++i)
    {
        int x,y,w;
        cin>>x>>y>>w;
        v[x].pb({w,y});
        g[y].pb({w,x});
    }
    for(int i=1;i<=n;++i)
        sort(all(v[i])),sort(all(g[i]));
    //vector<map<int,int>> fr(k+1);
    //set<pair<pii,pii>> s;
    for(int i=1;i<=n;++i)
    {
        //vector<int> lb(k+1,0);
        //cout<<i<<"\n";
        vector<pii> lb;
        for(auto j:g[i])
        {
            pii x = {j.F,i};
            auto it=lower_bound(all(v[j.S]),x)-v[j.S].begin();
            ++it;
            assert(it<=sz(v[j.S]));
            lb.pb({sz(v[j.S]),it});
            //cout<<sz(v[j.S])<<" "<<it<<"\n";
            //++lb[it];
        }
        int nn=sz(lb);
        for(int j=0;j<nn;++j)
        {
            for(int k=0;k<nn;++k)
            {
                if(k==j)continue;
                if(lb[j]==lb[k])
                    check[lb[j]]=true;
                else
                    mp[lb[j]][lb[k]]=true,mp[lb[k]][lb[j]]=true;
            }
        }

    }
    //cout<<lower_bound(all(v[4]),{2,2})-v[4].begin()<<"\n";
    //cout << k <<"\n";
    vector<int> xx(k+1,0);
    int ans = go(1,xx);
    assert(ans>=0);
    cout<<ans<<"\n";
    return 0;
}

int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    #ifdef runSieve
        sieve();
    #endif
    #ifdef NCR
        initialize();
    #endif
    int TESTS=1;
    //cin>>TESTS;
    while(TESTS--)
        _runtimeTerror_();
    return 0;
}


#include<bits/stdc++.h>
using namespace std ;

#define ll long long
#define pb push_back
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define memf(a) memset(a,false,sizeof(a))
#define all(v) v.begin(),v.end()
#define sz(a) (ll)a.size()
#define F first
#define S second
#define INF 2000000000000000000
#define endl "\n"
#define _time_ 1.0 * clock() / CLOCKS_PER_SEC
#define popcount(x) __builtin_popcountll(x)
#define pll pair<ll,ll>
#define ld long double

const int M=1000000007;
const int MM=998244353;
const long double PI = acos(-1);

ll power(ll b,ll e,ll m)
{
    if(e==0) return 1;
    if(e&1) return b*power(b*b%m,e/2,m)%m;
    return power(b*b%m,e/2,m);
}
ll power( ll b, ll e)
{
    if(e==0) return 1;
    if(e&1) return b*power(b*b,e/2);
    return power(b*b,e/2);
}
template<typename T, typename U> static inline void amin(T &x, U y){ if(y<x) x=y; }
template<typename T, typename U> static inline void amax(T &x, U y){ if(x<y) x=y; }
template<typename T, typename U> ostream& operator<<(ostream &os, const pair<T, U> &p)
{
    return os<<'('<<p.F<< ","<<p.S<<')';
}
#define pii pair<int,int>
const int N=200005;
int n,m,k;

vector<pii> v[N],g[N];

map<pii,map<pii,bool>> mp;
map<pii,bool> check;

int go(int pos,vector<int> kx)
{
    //cout<<pos<<"\n";
    if(pos==k+1)
        return 1;
    int ans=0;
    vector<int> t=kx;
    if(pos==1)
    {
        t[1]=1;
        return go(pos+1,t);
    }
    for(int j=1;j<=pos;++j)
    {
        if(check[{pos,j}])
            continue;
        bool f=false;
        for(int kk=1;kk<pos;++kk)
        {
            if(mp[{pos,j}][{kk,kx[kk]}])
                f=true;
        }
        if(!f)
        {
            t[pos]=j;
            ans+=go(pos+1,t);
        }
    }
    //cout<<pos<<" ";
    //cout<<ans<<"\n";
    return ans;
}

int _runtimeTerror_()
{
    cin>>n>>m>>k;
    for(int i=0;i<m;++i)
    {
        int x,y,w;
        cin>>x>>y>>w;
        v[x].pb({w,y});
        g[y].pb({w,x});
    }
    for(int i=1;i<=n;++i)
        sort(all(v[i])),sort(all(g[i]));
    //vector<map<int,int>> fr(k+1);
    //set<pair<pii,pii>> s;
    for(int i=1;i<=n;++i)
    {
        //vector<int> lb(k+1,0);
        //cout<<i<<"\n";
        vector<pii> lb;
        for(auto j:g[i])
        {
            pii x = {j.F,i};
            auto it=lower_bound(all(v[j.S]),x)-v[j.S].begin();
            ++it;
            assert(it<=sz(v[j.S]));
            lb.pb({sz(v[j.S]),it});
            //cout<<sz(v[j.S])<<" "<<it<<"\n";
            //++lb[it];
        }
        if(lb.empty())
        {
            cout<<0;return 0;
        }
        int nn=sz(lb);
        for(int j=0;j<nn;++j)
        {
            for(int k=0;k<nn;++k)
            {
                if(k==j)continue;
                if(lb[j]==lb[k])
                    check[lb[j]]=true;
                else
                    mp[lb[j]][lb[k]]=true,mp[lb[k]][lb[j]]=true;
            }
        }

    }
    //cout<<lower_bound(all(v[4]),{2,2})-v[4].begin()<<"\n";
    //cout << k <<"\n";
    vector<int> xx(k+1,0);
    int ans = go(1,xx);
    assert(ans>=0);
    cout<<ans<<"\n";
    return 0;
}

int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    #ifdef runSieve
        sieve();
    #endif
    #ifdef NCR
        initialize();
    #endif
    int TESTS=1;
    //cin>>TESTS;
    while(TESTS--)
        _runtimeTerror_();
    return 0;
}


#include<bits/stdc++.h>
using namespace std ;

#define ll long long
#define pb push_back
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define memf(a) memset(a,false,sizeof(a))
#define all(v) v.begin(),v.end()
#define sz(a) (ll)a.size()
#define F first
#define S second
#define INF 2000000000000000000
#define endl "\n"
#define _time_ 1.0 * clock() / CLOCKS_PER_SEC
#define popcount(x) __builtin_popcountll(x)
#define pll pair<ll,ll>
#define ld long double

const int M=1000000007;
const int MM=998244353;
const long double PI = acos(-1);

ll power(ll b,ll e,ll m)
{
    if(e==0) return 1;
    if(e&1) return b*power(b*b%m,e/2,m)%m;
    return power(b*b%m,e/2,m);
}
ll power( ll b, ll e)
{
    if(e==0) return 1;
    if(e&1) return b*power(b*b,e/2);
    return power(b*b,e/2);
}
template<typename T, typename U> static inline void amin(T &x, U y){ if(y<x) x=y; }
template<typename T, typename U> static inline void amax(T &x, U y){ if(x<y) x=y; }
template<typename T, typename U> ostream& operator<<(ostream &os, const pair<T, U> &p)
{
    return os<<'('<<p.F<< ","<<p.S<<')';
}
#define pii pair<int,int>
const int N=200005;
int n,m,k;

vector<pii> v[N],g[N];

bool mp[10][10][10][10];

bool check[10][10];

//map<pii,map<pii,bool>> mp;
//map<pii,bool> check;
vector<int> kx;

int go(int pos)
{
    //cout<<pos<<"\n";
    if(pos==k+1)
        return 1;
    int ans=0;
    //vector<int> t=kx;
    if(pos==1)
    {
        if(check[1][1])
            return 0;
        kx.pb(1);
        return go(pos+1);
    }
    for(int j=1;j<=pos;++j)
    {
        if(check[pos][j])
            continue;
        bool f=false;
        for(int kk=1;kk<pos;++kk)
        {
            if(mp[pos][j][kk][kx[kk-1]])
                f=true;
        }
        if(!f)
        {
            kx.pb(j);
            ans+=go(pos+1);
            kx.pop_back();
        }
    }
    //cout<<pos<<" ";
    //cout<<ans<<"\n";
    return ans;
}

int _runtimeTerror_()
{
    cin>>n>>m>>k;
    for(int i=0;i<m;++i)
    {
        int x,y,w;
        cin>>x>>y>>w;
        v[x].pb({w,y});
        g[y].pb({w,x});
    }
    for(int i=1;i<=n;++i)
        sort(all(v[i])),sort(all(g[i]));
    //vector<map<int,int>> fr(k+1);
    //set<pair<pii,pii>> s;
    for(int i=1;i<=n;++i)
    {
        //vector<int> lb(k+1,0);
        //cout<<i<<"\n";
        vector<pii> lb;
        for(auto j:g[i])
        {
            pii x = {j.F,i};
            auto it=lower_bound(all(v[j.S]),x)-v[j.S].begin();
            ++it;
            assert(it<=sz(v[j.S]));
            lb.pb({sz(v[j.S]),it});
            //cout<<sz(v[j.S])<<" "<<it<<"\n";
            //++lb[it];
        }
        if(lb.empty())
        {
            cout<<0;return 0;
        }
        int nn=sz(lb);
        sort(all(lb));
        lb.resize(unique(all(lb))-lb.begin());
        for(int j=0;j<nn;++j)
        {
            for(int k=0;k<nn;++k)
            {
                if(k==j)continue;
                if(lb[j]==lb[k])
                    check[lb[j].F][lb[j].S]=true;
                else
                    mp[lb[j].F][lb[j].S][lb[k].F][lb[k].S]=mp[lb[k].F][lb[k].S][lb[j].F][lb[j].S]=true;
            }
        }

    }
    //cout<<lower_bound(all(v[4]),{2,2})-v[4].begin()<<"\n";
    //cout << k <<"\n";
    vector<int> xx(k+1,0);
    int ans = go(1);
    assert(ans>=0);
    cout<<ans<<"\n";
    return 0;
}

int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    #ifdef runSieve
        sieve();
    #endif
    #ifdef NCR
        initialize();
    #endif
    int TESTS=1;
    //cin>>TESTS;
    while(TESTS--)
        _runtimeTerror_();
    return 0;
}


#line 1 "b.cpp"
// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

#line 4 "/mnt/c/Users/tkmma/competitive_programming/CPBF/library/include/unionfind.hpp"

class UnionFind {
 private:
  std::vector<int> par_,sz_;

 public:
  explicit UnionFind(size_t size) : par_(size), sz_(size, 1) {
    std::iota(par_.begin(), par_.end(), 0);
  }

  int root(int u) {
    if (u == par_[u])
      return u;
    return par_[u] = root(par_[u]);
  }

  bool are_union(int u, int v) {
    return root(u) == root(v);
  }

  int size_of(int u) {
    return sz_[root(u)];
  }

  bool unite(int u, int v) {
    if (are_union(u,v))
      return false;
    if (size_of(u) < size_of(v))
      std::swap(u,v);
    sz_[root(u)] += size_of(v);
    par_[root(v)] = root(u);
    return true;
  }

};

#line 10 "b.cpp"

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  UnionFind uf(n);
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
    uf.unite(u,v);
  }
  for (int i = 0; i < n; i++) {
    sort(graph[i].begin(), graph[i].end(), [](auto l, auto r) {
      return l.w<r.w;
    });
  }
  vector<int> rs;
  for (int i = 0; i < n; i++) {
    if (uf.root(i) == i)
      rs.push_back(i);
  }

  vector<int> C(k, -1);
  vector<bool> vis(n, false);
  ll ans = 0;
  auto dfs = [&graph, &ans, k, &vis, &C, &uf, &rs](auto f, int s, int cnt, int id) -> void {
    if (cnt == uf.size_of(s) and s == rs[id]) {
      if (id == rs.size()-1) {
        ll v = 1;
        for (int i = 0; i < k; i++) {
          if (C[i] == -1)
            v *= i+1;
        }
        ans += v;
      } else {
        f(f, rs[id+1], 0, id+1);
      }
      return;
    }
    if (vis[s])
      return;
    vis[s] = true;
    if (!graph[s].empty()) {
      int c = graph[s].size();
      if (C[c-1] == -1) {
        for (int m = 0; m < c; m++) {
          C[c-1] = m;
          f(f, graph[s][m].t, cnt+1, id);
        }
        C[c-1] = -1;
      } else {
        f(f, graph[s][C[c-1]].t, cnt+1, id);
      }
    }
    vis[s] = false;
  };
  dfs(dfs, rs[0], 0, 0);
  cout << ans << endl;

  return 0;
}


// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

#include "../../../library/include/unionfind.hpp"

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  UnionFind uf(n);
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
    uf.unite(u,v);
  }
  for (int i = 0; i < n; i++) {
    sort(graph[i].begin(), graph[i].end(), [](auto l, auto r) {
      return l.w<r.w;
    });
  }
  vector<int> rs;
  for (int i = 0; i < n; i++) {
    if (uf.root(i) == i)
      rs.push_back(i);
  }

  vector<int> C(k, -1);
  vector<bool> vis(n, false);
  ll ans = 0;
  auto dfs = [&graph, &ans, k, &vis, &C, &uf, &rs](auto f, int s, int cnt, int id) -> void {
    if (cnt == uf.size_of(s) and s == rs[id]) {
      if (id == rs.size()-1) {
        ll v = 1;
        for (int i = 0; i < k; i++) {
          if (C[i] == -1)
            v *= i+1;
        }
        ans += v;
      } else {
        f(f, rs[id+1], 0, id+1);
      }
      return;
    }
    if (vis[s])
      return;
    vis[s] = true;
    if (!graph[s].empty()) {
      int c = graph[s].size();
      if (C[c-1] == -1) {
        for (int m = 0; m < c; m++) {
          C[c-1] = m;
          f(f, graph[s][m].t, cnt+1, id);
        }
        C[c-1] = -1;
      } else {
        f(f, graph[s][C[c-1]].t, cnt+1, id);
      }
    }
    vis[s] = false;
  };
  dfs(dfs, rs[0], 0, 0);
  cout << ans << endl;

  return 0;
}


#line 1 "b.cpp"
// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

#line 3 "/mnt/c/Users/tkmma/competitive_programming/CPBF/library/include/modular.hpp"

template <long long MOD>
class Modular {
 private:
  long long val_;

 public:
  constexpr Modular() : val_(0) {}
  constexpr Modular(long long v) : val_(v%MOD) {
    if (val_ < 0) val_ += MOD;
  }

  constexpr long long val() const { return val_; }
  constexpr Modular operator+(Modular x) const { return (val() + x.val())%MOD; }
  constexpr Modular operator+=(Modular x) { return *this = *this + x; }
  constexpr Modular operator++() { return *this += 1; }
  constexpr Modular operator++(int) { Modular c = *this; ++(*this); return c; }
  constexpr Modular operator-(Modular x) const { return (val() + MOD - x.val())%MOD; }
  constexpr Modular operator-=(Modular x) { return *this = *this - x; }
  constexpr Modular operator--() { return *this -= 1; }
  constexpr Modular operator--(int) { Modular c = *this; --(*this); return c; }
  constexpr Modular operator*(Modular x) const { return (val() * x.val())%MOD; }
  constexpr Modular operator*=(Modular x) { return *this = *this * x; }
  friend constexpr Modular pow(Modular x, long long p) {
    Modular t = 1;
    Modular u = x;
    while (p) {
      if (p & 1)
        t *= u;
      u *= u;
      p >>= 1;
    }
    return t;
  }
  constexpr Modular operator/(Modular x) const { return *this * pow(Modular{x}, MOD-2); }
  constexpr Modular operator/=(Modular x) { return *this = *this / x; }

  constexpr bool operator==(Modular x) const { return val() == x.val(); }
  constexpr bool operator!=(Modular x) const { return val() != x.val(); }
  constexpr bool operator<(Modular x) const { return val() < x.val(); };
  constexpr bool operator<=(Modular x) const { return val() <= x.val(); };
  constexpr bool operator>(Modular x) const { return val() > x.val(); };
  constexpr bool operator>=(Modular x) const { return val() >= x.val(); };

  friend std::ostream& operator<<(std::ostream& os, const Modular& x) {
    return os << x.val();
  }
  friend std::istream& operator>>(std::istream& is, Modular& x) {
    return is >> x.val_;
  }

};

#line 10 "b.cpp"

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
  }
  constexpr int MOD = 1e9+7;
  using Mint = Modular<MOD>;
  constexpr Mint BASE = 2;
  Mint anshash = 0;
  for (int i = 0; i < n; i++) {
    anshash += pow(BASE, i);
  }
  vector<vector<Mint>> hs(k, vector<Mint>(k));
  for (auto& out:graph) {
    sort(out.begin(), out.end(), [](auto l, auto r) {
      return l.w < r.w;
    });
    for (int i = 0; i < out.size(); i++) {
      hs[out.size()-1][i] += pow(BASE, out[i].t);
    }
  }

  vector<int> C(k, -1);
  int ans = 0;
  auto solve = [&]() {
    Mint hash = 0;
    for (int i = 0; i < k; i++) {
      hash += hs[i][C[i]];
    }
    if (hash == anshash)
      ans++;
  };
  auto rec = [&](auto f, int len) -> void {
    if (len == k) {
      solve();
      return;
    }
    for (int i = 0; i <= len; i++) {
      C[len] = i;
      f(f, len+1);
    }
  };
  rec(rec, 0);
  cout << ans << endl;

  return 0;
}


#line 1 "b.cpp"
// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

#line 4 "/mnt/c/Users/tkmma/competitive_programming/CPBF/library/include/unionfind.hpp"

class UnionFind {
 private:
  std::vector<int> par_,sz_;

 public:
  explicit UnionFind(size_t size) : par_(size), sz_(size, 1) {
    std::iota(par_.begin(), par_.end(), 0);
  }

  int root(int u) {
    if (u == par_[u])
      return u;
    return par_[u] = root(par_[u]);
  }

  bool are_union(int u, int v) {
    return root(u) == root(v);
  }

  int size_of(int u) {
    return sz_[root(u)];
  }

  bool unite(int u, int v) {
    if (are_union(u,v))
      return false;
    if (size_of(u) < size_of(v))
      std::swap(u,v);
    sz_[root(u)] += size_of(v);
    par_[root(v)] = root(u);
    return true;
  }

};

#line 10 "b.cpp"

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  UnionFind uf(n);
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
    uf.unite(u,v);
  }
  for (int i = 0; i < n; i++) {
    sort(graph[i].begin(), graph[i].end(), [](auto l, auto r) {
      return l.w < r.w;
    });
  }
  vector<int> rs;
  for (int i = 0; i < n; i++) {
    if (uf.root(i) == i)
      rs.push_back(i);
  }

  vector<int> C(k, -1);
  vector<bool> vis(n);
  int ans = 0;
  auto dfs = [&graph, &ans, k, &vis, &C, &uf, &rs](auto f, int s, int cnt, int id) -> void {
    if (cnt == uf.size_of(s) and s == rs[id]) {
      if (id+1 == rs.size()) {
        int c = 1;
        for (int i = 0; i < k; i++) {
          if (C[i] == -1)
            c *= i+1;
        }
        ans += c;
      } else {
        f(f, rs[id+1], 0, id+1);
      }
      return;
    }
    if (vis[s])
      return;
    vis[s] = true;
    int sz = graph[s].size();
    if (C[sz-1] == -1) {
      for (int i = 0; i < sz; i++) {
        C[sz-1] = i;
        f(f, graph[s][i].t, cnt+1, id);
      }
      C[sz-1] = -1;
    } else {
      f(f, graph[s][C[sz-1]].t, cnt+1, id);
    }
    vis[s] = false;
  };
  dfs(dfs, rs[0], 0, 0);
  cout << ans << endl;

  return 0;
}


#line 1 "b.cpp"
// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

#line 4 "/mnt/c/Users/tkmma/competitive_programming/CPBF/library/include/unionfind.hpp"

class UnionFind {
 private:
  std::vector<int> par_,sz_;

 public:
  explicit UnionFind(size_t size) : par_(size), sz_(size, 1) {
    std::iota(par_.begin(), par_.end(), 0);
  }

  int root(int u) {
    if (u == par_[u])
      return u;
    return par_[u] = root(par_[u]);
  }

  bool are_union(int u, int v) {
    return root(u) == root(v);
  }

  int size_of(int u) {
    return sz_[root(u)];
  }

  bool unite(int u, int v) {
    if (are_union(u,v))
      return false;
    if (size_of(u) < size_of(v))
      std::swap(u,v);
    sz_[root(u)] += size_of(v);
    par_[root(v)] = root(u);
    return true;
  }

};

#line 10 "b.cpp"

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  UnionFind uf(n);
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
    uf.unite(u,v);
  }
  for (auto& out:graph) {
    sort(out.begin(), out.end(), [](auto l, auto r) {
      return l.w < r.w;
    });
  }
  vector<int> rs;
  for (int i = 0; i < n; i++) {
    if (uf.root(i) == i)
      rs.push_back(i);
  }

  vector<int> C(k, -1);
  vector<bool> vis(n);
  auto dfs = [&graph, k, &vis, &C, &uf, &rs](auto f, int s, int cnt, int id) {
    if (cnt == uf.size_of(s) and s == rs[id]) {
      if (id+1 == rs.size()) {
        int c = 1;
        for (int i = 0; i < k; i++) {
          if (C[i] == -1)
            c *= i+1;
        }
        return c;
      } else {
        return f(f, rs[id+1], 0, id+1);
      }
    }
    if (vis[s])
      return 0;
    vis[s] = true;
    int sz = graph[s].size();
    auto& ord = C[sz-1];
    int ret = 0;
    if (ord == -1) {
      for (int i = 0; i < sz; i++) {
        ord = i;
        ret += f(f, graph[s][i].t, cnt+1, id);
      }
      ord = -1;
    } else {
      ret += f(f, graph[s][ord].t, cnt+1, id);
    }
    vis[s] = false;
    return ret;
  };
  int ans = dfs(dfs, rs[0], 0, 0);
  cout << ans << endl;

  return 0;
}


#line 1 "b.cpp"
// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

#line 3 "/mnt/c/Users/tkmma/competitive_programming/CPBF/library/include/modular.hpp"

template <long long MOD>
class Modular {
 private:
  long long val_;

 public:
  constexpr Modular() : val_(0) {}
  constexpr Modular(long long v) : val_(v%MOD) {
    if (val_ < 0) val_ += MOD;
  }

  constexpr long long val() const { return val_; }
  constexpr Modular operator+(Modular x) const { return (val() + x.val())%MOD; }
  constexpr Modular operator+=(Modular x) { return *this = *this + x; }
  constexpr Modular operator++() { return *this += 1; }
  constexpr Modular operator++(int) { Modular c = *this; ++(*this); return c; }
  constexpr Modular operator-(Modular x) const { return (val() + MOD - x.val())%MOD; }
  constexpr Modular operator-=(Modular x) { return *this = *this - x; }
  constexpr Modular operator--() { return *this -= 1; }
  constexpr Modular operator--(int) { Modular c = *this; --(*this); return c; }
  constexpr Modular operator*(Modular x) const { return (val() * x.val())%MOD; }
  constexpr Modular operator*=(Modular x) { return *this = *this * x; }
  friend constexpr Modular pow(Modular x, long long p) {
    Modular t = 1;
    Modular u = x;
    while (p) {
      if (p & 1)
        t *= u;
      u *= u;
      p >>= 1;
    }
    return t;
  }
  constexpr Modular operator/(Modular x) const { return *this * pow(Modular{x}, MOD-2); }
  constexpr Modular operator/=(Modular x) { return *this = *this / x; }

  constexpr bool operator==(Modular x) const { return val() == x.val(); }
  constexpr bool operator!=(Modular x) const { return val() != x.val(); }
  constexpr bool operator<(Modular x) const { return val() < x.val(); };
  constexpr bool operator<=(Modular x) const { return val() <= x.val(); };
  constexpr bool operator>(Modular x) const { return val() > x.val(); };
  constexpr bool operator>=(Modular x) const { return val() >= x.val(); };

  friend std::ostream& operator<<(std::ostream& os, const Modular& x) {
    return os << x.val();
  }
  friend std::istream& operator>>(std::istream& is, Modular& x) {
    return is >> x.val_;
  }

};

#line 10 "b.cpp"

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
  }
  constexpr int MOD = 1e9+7;
  using Mint = Modular<MOD>;
  constexpr Mint BASE = 10007;
  Mint anshash = 0;
  for (int i = 0; i < n; i++) {
    anshash += pow(BASE, i);
  }
  vector<vector<Mint>> hs(k, vector<Mint>(k));
  for (auto& out:graph) {
    sort(out.begin(), out.end(), [](auto l, auto r) {
      return l.w < r.w;
    });
    for (int i = 0; i < out.size(); i++) {
      hs[out.size()-1][i] += pow(BASE, out[i].t);
    }
  }

  vector<int> C(k, -1);
  int ans = 0;
  auto solve = [&]() {
    Mint hash = 0;
    for (int i = 0; i < k; i++) {
      hash += hs[i][C[i]];
    }
    if (hash == anshash)
      ans++;
  };
  auto rec = [&](auto f, int len) -> void {
    if (len == k) {
      solve();
      return;
    }
    for (int i = 0; i <= len; i++) {
      C[len] = i;
      f(f, len+1);
    }
  };
  rec(rec, 0);
  cout << ans << endl;

  return 0;
}


#line 1 "b.cpp"
// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

#line 4 "/mnt/c/Users/tkmma/competitive_programming/CPBF/library/include/unionfind.hpp"

class UnionFind {
 private:
  std::vector<int> par_,sz_;

 public:
  explicit UnionFind(size_t size) : par_(size), sz_(size, 1) {
    std::iota(par_.begin(), par_.end(), 0);
  }

  int root(int u) {
    if (u == par_[u])
      return u;
    return par_[u] = root(par_[u]);
  }

  bool are_union(int u, int v) {
    return root(u) == root(v);
  }

  int size_of(int u) {
    return sz_[root(u)];
  }

  bool unite(int u, int v) {
    if (are_union(u,v))
      return false;
    if (size_of(u) < size_of(v))
      std::swap(u,v);
    sz_[root(u)] += size_of(v);
    par_[root(v)] = root(u);
    return true;
  }

};

#line 10 "b.cpp"

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  UnionFind uf(n);
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
    uf.unite(u,v);
  }
  for (int i = 0; i < n; i++) {
    sort(graph[i].begin(), graph[i].end(), [](auto l, auto r) {
      return l.w < r.w;
    });
  }
  vector<int> rs;
  for (int i = 0; i < n; i++) {
    if (uf.root(i) == i)
      rs.push_back(i);
  }

  vector<int> C(k, -1);
  vector<bool> vis(n);
  ll ans = 0;
  auto dfs = [&graph, &ans, k, &vis, &C, &uf, &rs](auto f, int s, int cnt, int id) -> void {
    if (cnt == uf.size_of(s) and s == rs[id]) {
      if (id == rs.size()-1) {
        ll v = 1;
        for (int i = 0; i < k; i++) {
          if (C[i] == -1)
            v *= i+1;
        }
        ans += v;
      } else {
        f(f, rs[id+1], 0, id+1);
      }
      return;
    }
    if (vis[s] or graph[s].empty())
      return;
    vis[s] = true;
    int c = graph[s].size();
    if (C[c-1] == -1) {
      for (int m = 0; m < c; m++) {
        C[c-1] = m;
        f(f, graph[s][m].t, cnt+1, id);
      }
      C[c-1] = -1;
    } else {
      f(f, graph[s][C[c-1]].t, cnt+1, id);
    }
    vis[s] = false;
  };
  dfs(dfs, rs[0], 0, 0);
  cout << ans << endl;

  return 0;
}


// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
  }
  for (int i = 0; i < n; i++) {
    sort(graph[i].begin(), graph[i].end(), [](auto l, auto r) {
      return l.w<r.w;
    });
  }

  vector<int> C(k, -1);
  vector<bool> vis(n, false);
  ll ans = 0;
  auto dfs = [&graph, &ans, n,k, &vis, &C](auto f, int s, int cnt=1) {
    if (cnt == n and s == 0) {
      ll v = 1;
      for (int i = 0; i < k; i++) {
        if (C[i] == -1)
          v *= i+1;
      }
      ans += v;
      return;
    }
    if (vis[s])
      return;
    vis[s] = true;
    if (!graph[s].empty()) {
      int c = graph[s].size();
      if (C[c-1] == -1) {
        for (int m = 0; m < c; m++) {
          C[c-1] = m;
          f(f, graph[s][m].t, cnt+1);
        }
        C[c-1] = -1;
      } else {
        f(f, graph[s][C[c-1]].t, cnt+1);
      }
    }
    vis[s] = false;
  };
  dfs(dfs, 0, 0);
  cout << ans << endl;

  return 0;
}


// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

#include "../../../library/include/unionfind.hpp"

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  UnionFind uf(n);
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
    uf.unite(u,v);
  }
  for (int i = 0; i < n; i++) {
    sort(graph[i].begin(), graph[i].end(), [](auto l, auto r) {
      return l.w < r.w;
    });
  }
  vector<int> rs;
  for (int i = 0; i < n; i++) {
    if (uf.root(i) == i)
      rs.push_back(i);
  }

  vector<int> C(k, -1);
  vector<bool> vis(n);
  ll ans = 0;
  auto dfs = [&graph, &ans, k, &vis, &C, &uf, &rs](auto f, int s, int cnt, int id) -> void {
    if (cnt == uf.size_of(s) and s == rs[id]) {
      if (id == rs.size()-1) {
        ll v = 1;
        for (int i = 0; i < k; i++) {
          if (C[i] == -1)
            v *= i+1;
        }
        ans += v;
      } else {
        f(f, rs[id+1], 0, id+1);
      }
      return;
    }
    if (vis[s] or graph[s].empty())
      return;
    vis[s] = true;
    int c = graph[s].size();
    if (C[c-1] == -1) {
      for (int m = 0; m < c; m++) {
        C[c-1] = m;
        f(f, graph[s][m].t, cnt+1, id);
      }
      C[c-1] = -1;
    } else {
      f(f, graph[s][C[c-1]].t, cnt+1, id);
    }
    vis[s] = false;
  };
  dfs(dfs, rs[0], 0, 0);
  cout << ans << endl;

  return 0;
}


#line 1 "b.cpp"
// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

#line 4 "/mnt/c/Users/tkmma/competitive_programming/CPBF/library/include/unionfind.hpp"

class UnionFind {
 private:
  std::vector<int> par_,sz_;

 public:
  explicit UnionFind(size_t size) : par_(size), sz_(size, 1) {
    std::iota(par_.begin(), par_.end(), 0);
  }

  int root(int u) {
    if (u == par_[u])
      return u;
    return par_[u] = root(par_[u]);
  }

  bool are_union(int u, int v) {
    return root(u) == root(v);
  }

  int size_of(int u) {
    return sz_[root(u)];
  }

  bool unite(int u, int v) {
    if (are_union(u,v))
      return false;
    if (size_of(u) < size_of(v))
      std::swap(u,v);
    sz_[root(u)] += size_of(v);
    par_[root(v)] = root(u);
    return true;
  }

};

#line 10 "b.cpp"

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  UnionFind uf(n);
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
    uf.unite(u,v);
  }
  for (int i = 0; i < n; i++) {
    sort(graph[i].begin(), graph[i].end(), [](auto l, auto r) {
      return l.w < r.w;
    });
  }
  vector<int> rs;
  for (int i = 0; i < n; i++) {
    if (uf.root(i) == i)
      rs.push_back(i);
  }

  vector<int> C(k, -1);
  vector<bool> vis(n);
  ll ans = 0;
  auto dfs = [&graph, &ans, k, &vis, &C, &uf, &rs](auto f, int s, int cnt, int id) -> void {
    if (cnt == uf.size_of(s) and s == rs[id]) {
      int nid = id+1;
      while (nid < rs.size() and uf.size_of(rs[nid]) == 1)
        nid++;
      if (nid == rs.size()) {
        ll v = 1;
        for (int i = 0; i < k; i++) {
          if (C[i] == -1)
            v *= i+1;
        }
        ans += v;
      } else {
        f(f, rs[nid], 0, nid);
      }
      return;
    }
    if (vis[s] or graph[s].empty())
      return;
    vis[s] = true;
    int c = graph[s].size();
    if (C[c-1] == -1) {
      for (int m = 0; m < c; m++) {
        C[c-1] = m;
        f(f, graph[s][m].t, cnt+1, id);
      }
      C[c-1] = -1;
    } else {
      f(f, graph[s][C[c-1]].t, cnt+1, id);
    }
    vis[s] = false;
  };
  dfs(dfs, rs[0], 0, 0);
  cout << ans << endl;

  return 0;
}


// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
  }
  for (auto& out:graph) {
    sort(out.begin(), out.end(), [](auto l, auto r) {
      return l.w < r.w;
    });
  }

  vector<int> C(k, -1);
  vector<bool> vis(n);
  int ans = 0;
  auto dfs = [&graph, &C, &vis, n, &ans](auto f, int s, int cnt) {
    if (cnt == n and s == 0) {
      ans++;
//      for (auto c:C)
//        cerr<<c<<" ";
//      cerr<<endl;
      return;
    }
    if (vis[s])
      return;
    vis[s] = true;
    int sz = graph[s].size();
    f(f, graph[s][C[sz-1]].t, cnt+1);
    vis[s] = false;
  };
  auto create_tuple = [&](auto f, int len) {
    if (len == k) {
      dfs(dfs, 0, 0);
      return;
    }
    for (int i = 0; i <= len; i++) {
      C[len] = i;
      f(f, len+1);
    }
  };
  create_tuple(create_tuple, 0);
  cout << ans << endl;

  return 0;
}


// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

#include "../../../library/include/unionfind.hpp"

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  UnionFind uf(n);
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
    uf.unite(u,v);
  }
  for (auto& out:graph) {
    sort(out.begin(), out.end(), [](auto l, auto r) {
      return l.w < r.w;
    });
  }
  vector<int> rs;
  for (int i = 0; i < n; i++) {
    if (uf.root(i) == i)
      rs.push_back(i);
  }

  vector<int> C(k, -1);
  vector<bool> vis(n);
  auto dfs = [&graph, k, &vis, &C, &uf, &rs](auto f, int s, int cnt, int id) {
    if (cnt == uf.size_of(s) and s == rs[id]) {
      if (id+1 == rs.size()) {
        int c = 1;
        for (int i = 0; i < k; i++) {
          if (C[i] == -1)
            c *= i+1;
        }
        return c;
      } else {
        return f(f, rs[id+1], 0, id+1);
      }
    }
    if (vis[s])
      return 0;
    vis[s] = true;
    int sz = graph[s].size();
    auto& ord = C[sz-1];
    int ret = 0;
    if (ord == -1) {
      for (int i = 0; i < sz; i++) {
        ord = i;
        ret += f(f, graph[s][i].t, cnt+1, id);
      }
      ord = -1;
    } else {
      ret += f(f, graph[s][ord].t, cnt+1, id);
    }
    vis[s] = false;
    return ret;
  };
  int ans = dfs(dfs, rs[0], 0, 0);
  cout << ans << endl;

  return 0;
}


#line 1 "b.cpp"
// -----------------------------------
// author   : MatsuTaku
// country  : Japan
// created  : 08/12/20 23:28:39
// -----------------------------------

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);

  int n,m,k; cin>>n>>m>>k;
  struct Edge {
    int t,w;
  };
  vector<Edge> graph[n];
  for (int i = 0; i < m; i++) {
    int u,v,w; cin>>u>>v>>w; u--; v--;
    graph[u].push_back({v,w});
  }
  for (auto& out:graph) {
    sort(out.begin(), out.end(), [](auto l, auto r) {
      return l.w < r.w;
    });
  }

  vector<int> C(k, -1);
  vector<bool> vis(n);
  auto dfs = [&graph, k, n, &vis, &C](auto f, int s, int cnt) {
    if (cnt == n and s == 0) {
      int c = 1;
      for (int i = 0; i < k; i++) {
        if (C[i] == -1)
          c *= i+1;
      }
      return c;
    }
    if (vis[s])
      return 0;
    vis[s] = true;
    int sz = graph[s].size();
    auto& ord = C[sz-1];
    int ret = 0;
    if (ord == -1) {
      for (int i = 0; i < sz; i++) {
        ord = i;
        ret += f(f, graph[s][i].t, cnt+1);
      }
      ord = -1;
    } else {
      ret += f(f, graph[s][ord].t, cnt+1);
    }
    vis[s] = false;
    return ret;
  };
  int ans = dfs(dfs, 0, 0);
  cout << ans << endl;

  return 0;
}


#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<cassert>
#include<cassert>
#include<unordered_map>
#include<unordered_set>
#include<functional>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<sstream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<numeric>
#include<random>
#include<chrono>
#include<bitset>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define pb push_back
#define xx first
#define yy second
#define sz(x) (int)(x).size()
#define gc getchar
#define IO ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mp make_pair

#ifndef ONLINE_JUDGE
#  define LOG(x) (cerr << #x << " = " << (x) << endl)
#else
#  define LOG(x) ((void)0)
#endif

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const double PI=acos(-1);
const ll INF = 1LL<<62;
const ll MINF = -(1LL<<62);

template<typename T> T getint() {
	T val=0;
	char c;

	bool neg=false;
	while((c=gc()) && !(c>='0' && c<='9')) {
		neg|=c=='-';
	}

	do {
		val=(val*10)+c-'0';
	} while((c=gc()) && (c>='0' && c<='9'));

	return val*(neg?-1:1);
}

//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); uniform_int_distribution<int>(0, n-1)(rng)

int n,m,k;
const int MAXN=200001;
vector<pair<int,int>> adj[MAXN];
//~ int akt[MAXN];
//~ int sum=0;
//~ void toggle(int x) {
	//~ sum-=akt[x];
	//~ akt[x]^=1;
	//~ sum+=akt[x];
//~ }
bitset<MAXN> bs[9][9];
vector<int> lst[MAXN];
int ans=0;
bitset<MAXN> akt;
const int MAGIC=200;
void gen(int x) {
	if(x>k) {
		if((int)akt.count()==n) ans++;
		return ;
	}

	for(int i=1;i<=x;++i) {
		if(sz(lst[x])>=MAGIC)
			akt^=bs[x-1][i-1];
		else {
			for(int j=0;j<sz(lst[x]);++j) {
				akt.flip(adj[lst[x][j]][i-1].yy);
			}
		}

		gen(x+1);
		if(sz(lst[x])>=MAGIC)
			akt^=bs[x-1][i-1];
		else {
			for(int j=0;j<sz(lst[x]);++j) {
				akt.flip(adj[lst[x][j]][i-1].yy);
			}
		}

		//~ LOG(x);
		//~ LOG(i);
		//~ for(int j=0;j<sz(lst[x]);++j) {
			//~ toggle(lst[x][j]);
			//~ toggle(adj[lst[x][j]][i-1].yy);
		//~ }

		//~ gen(x+1);

		//~ for(int j=0;j<sz(lst[x]);++j) {
			//~ toggle(lst[x][j]);
			//~ toggle(adj[lst[x][j]][i-1].yy);
		//~ }
	}
}

int main() {
	IO;
	cin>>n>>m>>k;
	for(int i=0;i<m;++i) {
		int a,b,c;
		cin>>a>>b>>c;
		adj[a].pb({c,b});
	}

	for(int i=1;i<=n;++i) {
		sort(all(adj[i]));
		lst[sz(adj[i])].pb(i);
		for(int j=0;j<sz(adj[i]);++j) {
			bs[sz(adj[i])-1][j].flip(adj[i][j].yy);
			//~ in[adj[i][j].yy].push_back({sz(adj[i]), j+1});
		}
	}

	gen(1);
	cout<<ans<<"\n";
	return 0;
}


#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<cassert>
#include<cassert>
#include<unordered_map>
#include<unordered_set>
#include<functional>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<sstream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<numeric>
#include<random>
#include<chrono>
#include<bitset>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define pb push_back
#define xx first
#define yy second
#define sz(x) (int)(x).size()
#define gc getchar
#define IO ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mp make_pair

#ifndef ONLINE_JUDGE
#  define LOG(x) (cerr << #x << " = " << (x) << endl)
#else
#  define LOG(x) ((void)0)
#endif

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const double PI=acos(-1);
const ll INF = 1LL<<62;
const ll MINF = -(1LL<<62);

template<typename T> T getint() {
	T val=0;
	char c;

	bool neg=false;
	while((c=gc()) && !(c>='0' && c<='9')) {
		neg|=c=='-';
	}

	do {
		val=(val*10)+c-'0';
	} while((c=gc()) && (c>='0' && c<='9'));

	return val*(neg?-1:1);
}

//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); uniform_int_distribution<int>(0, n-1)(rng)

int n,m,k;
const int MAXN=200001;
vector<pair<int,int>> adj[MAXN];
int akt[MAXN];
int sum=0;
void toggle(int x) {
	sum-=akt[x];
	akt[x]^=1;
	sum+=akt[x];
}

vector<int> lst[MAXN];
int ans=0;
void gen(int x) {

	if(x>k) {
		if(sum==0) ans++;
		return ;
	}

	for(int i=1;i<=x;++i) {
		//~ LOG(x);
		//~ LOG(i);
		for(int j=0;j<sz(lst[x]);++j) {
			toggle(lst[x][j]);
			toggle(adj[lst[x][j]][i-1].yy);
		}

		gen(x+1);

		for(int j=0;j<sz(lst[x]);++j) {
			toggle(lst[x][j]);
			toggle(adj[lst[x][j]][i-1].yy);
		}
	}
}

int main() {
	IO;
	cin>>n>>m>>k;
	for(int i=0;i<m;++i) {
		int a,b,c;
		cin>>a>>b>>c;
		adj[a].pb({c,b});
	}

	for(int i=1;i<=n;++i) {
		sort(all(adj[i]));
		lst[sz(adj[i])].pb(i);
	}
	gen(1);
	cout<<ans<<"\n";
	return 0;
}


#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<cassert>
#include<cassert>
#include<unordered_map>
#include<unordered_set>
#include<functional>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<sstream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<numeric>
#include<random>
#include<chrono>
#include<bitset>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define pb push_back
#define xx first
#define yy second
#define sz(x) (int)(x).size()
#define gc getchar
#define IO ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mp make_pair

#ifndef ONLINE_JUDGE
#  define LOG(x) (cerr << #x << " = " << (x) << endl)
#else
#  define LOG(x) ((void)0)
#endif

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const double PI=acos(-1);
const ll INF = 1LL<<62;
const ll MINF = -(1LL<<62);

template<typename T> T getint() {
	T val=0;
	char c;

	bool neg=false;
	while((c=gc()) && !(c>='0' && c<='9')) {
		neg|=c=='-';
	}

	do {
		val=(val*10)+c-'0';
	} while((c=gc()) && (c>='0' && c<='9'));

	return val*(neg?-1:1);
}

//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); uniform_int_distribution<int>(0, n-1)(rng)

int n,m,k;
const int MAXN=200001;
vector<pair<int,int>> adj[MAXN];
//~ int akt[MAXN];
//~ int sum=0;
//~ void toggle(int x) {
	//~ sum-=akt[x];
	//~ akt[x]^=1;
	//~ sum+=akt[x];
//~ }
bitset<MAXN> bs[9][9];
vector<int> lst[MAXN];
int ans=0;
bitset<MAXN> akt;
void gen(int x) {
	if(x>k) {
		if(akt.count()==n) ans++;
		return ;
	}

	for(int i=1;i<=x;++i) {
		akt^=bs[x-1][i-1];
		gen(x+1);
		akt^=bs[x-1][i-1];
		//~ LOG(x);
		//~ LOG(i);
		//~ for(int j=0;j<sz(lst[x]);++j) {
			//~ toggle(lst[x][j]);
			//~ toggle(adj[lst[x][j]][i-1].yy);
		//~ }

		//~ gen(x+1);

		//~ for(int j=0;j<sz(lst[x]);++j) {
			//~ toggle(lst[x][j]);
			//~ toggle(adj[lst[x][j]][i-1].yy);
		//~ }
	}
}

int main() {
	IO;
	cin>>n>>m>>k;
	for(int i=0;i<m;++i) {
		int a,b,c;
		cin>>a>>b>>c;
		adj[a].pb({c,b});
	}

	for(int i=1;i<=n;++i) {
		sort(all(adj[i]));
		lst[sz(adj[i])].pb(i);
		for(int j=0;j<sz(adj[i]);++j) {
			bs[sz(adj[i])-1][j].flip(adj[i][j].yy);
			//~ in[adj[i][j].yy].push_back({sz(adj[i]), j+1});
		}
	}

	gen(1);
	cout<<ans<<"\n";
	return 0;
}


#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<cassert>
#include<cassert>
#include<unordered_map>
#include<unordered_set>
#include<functional>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<sstream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<numeric>
#include<random>
#include<chrono>
#include<bitset>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define pb push_back
#define xx first
#define yy second
#define sz(x) (int)(x).size()
#define gc getchar
#define IO ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mp make_pair

#ifndef ONLINE_JUDGE
#  define LOG(x) (cerr << #x << " = " << (x) << endl)
#else
#  define LOG(x) ((void)0)
#endif

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const double PI=acos(-1);
const ll INF = 1LL<<62;
const ll MINF = -(1LL<<62);

template<typename T> T getint() {
	T val=0;
	char c;

	bool neg=false;
	while((c=gc()) && !(c>='0' && c<='9')) {
		neg|=c=='-';
	}

	do {
		val=(val*10)+c-'0';
	} while((c=gc()) && (c>='0' && c<='9'));

	return val*(neg?-1:1);
}

//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); uniform_int_distribution<int>(0, n-1)(rng)

int n,m,k;
const int MAXN=200001;
vector<pair<int,int>> adj[MAXN];

int conv(int x, int y) {
	return x*k+y-1;
}
pair<int,int> iconv(int x) {
	return {x/k, x%k+1};
}

vector<int> in[MAXN];
int no[55][55];

int ans=0;
int curr[10];
void gen(int x) {
	if(x>k) {
		//~ for(int i=1;i<=k;++i) cerr<<curr[i]<<" ";cerr<<"\n";
		ans++;
		return ;
	}

	for(int i=1;i<=x;++i) {
		curr[x]=i;
		bool ok=true;
		for(int k=1;k<=x;++k) {
			ok&=no[conv(k,curr[k])][conv(x, i)]==0;
		}
		if(ok) gen(x+1);

	}
	curr[x]=0;
}

int main() {
	IO;
	cin>>n>>m>>k;
	for(int i=0;i<m;++i) {
		int a,b,c;
		cin>>a>>b>>c;
		adj[a].pb({c,b});
	}

	for(int i=1;i<=n;++i) {
		sort(all(adj[i]));
		for(int j=0;j<sz(adj[i]);++j) {
			in[adj[i][j].yy].pb(conv(sz(adj[i]), j+1));
		}
	}

	for(int i=1;i<=n;++i) {

		map<int,int> cnt;
		for(int j:in[i]) cnt[j]++;
		for(auto j:cnt) {
			if(j.yy>1) {
				no[j.xx][j.xx]=1;
			}
			for(auto k:cnt) {
				if(j.xx!=k.xx) {
					no[j.xx][k.xx]=1;
				}
			}
		}
	}

	gen(1);
	cout<<ans<<"\n";
	return 0;
}


#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<cassert>
#include<cassert>
#include<unordered_map>
#include<unordered_set>
#include<functional>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<sstream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<numeric>
#include<random>
#include<chrono>
#include<bitset>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define pb push_back
#define xx first
#define yy second
#define sz(x) (int)(x).size()
#define gc getchar
#define IO ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mp make_pair

#ifndef ONLINE_JUDGE
#  define LOG(x) (cerr << #x << " = " << (x) << endl)
#else
#  define LOG(x) ((void)0)
#endif

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const double PI=acos(-1);
const ll INF = 1LL<<62;
const ll MINF = -(1LL<<62);

template<typename T> T getint() {
	T val=0;
	char c;

	bool neg=false;
	while((c=gc()) && !(c>='0' && c<='9')) {
		neg|=c=='-';
	}

	do {
		val=(val*10)+c-'0';
	} while((c=gc()) && (c>='0' && c<='9'));

	return val*(neg?-1:1);
}

//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); uniform_int_distribution<int>(0, n-1)(rng)

int n,m,k;
const int MAXN=200001;
vector<pair<int,int>> adj[MAXN];

int conv(int x, int y) {
	return x*k+y-1;
}
pair<int,int> iconv(int x) {
	return {x/k, x%k+1};
}

vector<int> in[MAXN];
int no[500][500];

int ans=0;
int curr[500];
void gen(int x) {
	if(x>k) {
		//~ for(int i=1;i<=k;++i) cerr<<curr[i]<<" ";cerr<<"\n";
		ans++;
		return ;
	}

	for(int i=1;i<=x;++i) {
		curr[x]=i;
		bool ok=true;
		for(int k=1;k<=x;++k) {
			ok&=no[conv(k,curr[k])][conv(x, i)]==0;
		}
		if(ok) gen(x+1);

	}
	curr[x]=0;
}

int main() {
	IO;
	cin>>n>>m>>k;
	for(int i=0;i<m;++i) {
		int a,b,c;
		cin>>a>>b>>c;
		adj[a].pb({c,b});
	}

	for(int i=1;i<=n;++i) {
		sort(all(adj[i]));
		for(int j=0;j<sz(adj[i]);++j) {
			in[adj[i][j].yy].pb(conv(sz(adj[i]), j+1));
		}
	}

	for(int i=1;i<=n;++i) {

		map<int,int> cnt;
		for(int j:in[i]) cnt[j]++;
		for(auto j:cnt) {
			if(j.yy>1) {
				no[j.xx][j.xx]=1;
			}
			for(auto k:cnt) {
				if(j.xx!=k.xx) {
					no[j.xx][k.xx]=1;
				}
			}
		}
	}

	gen(1);
	cout<<ans<<"\n";
	return 0;
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef long double ld;
#define mp make_pair
#define pb push_back
int limit;

bool mat[10][10];
vector<vector<vector<vector<bool> > > >deleted;

ll backt(int i){
	if (i == limit + 1){
		return 1LL;
	}
	ll ans = 0LL;
	vector<vector<bool> > aux(10, vector<bool>(10, false));
	for (int k = 0; k < 10; k ++){
		for (int k2 = 0; k2 < 10; k2 ++){
			aux[k][k2] = mat[k][k2];
		}
	}
	for (int j = 0; j < i; j ++){
		if (mat[i][j] or deleted[i][j][i][j]) continue;
		for (int k = 0; k < 10; k ++){
			for (int k2 = 0; k2 < k; k2 ++){
				mat[k][k2] = mat[k][k2] | deleted[i][j][k][k2];
			}
		}
		ans += backt(i + 1);
		for (int k = 0; k < 10; k ++){
			for (int k2 = 0; k2 < k; k2 ++){
				mat[k][k2] = aux[k][k2];
			}
		}
	}
	return ans;
}

int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	for (int i = 0; i < 10; i ++){
		for (int j = 0; j < 10; j ++){
			mat[i][j] = false;
		}
	}
	int n, m, k;
	cin >> n >> m >> k;
	limit = k;
	vector<vector<pair<int, int> > >graph(n), invgraph(n);
	for (int i = 0; i < m; i ++){
		int a, b, w;
		cin >> a >> b >> w;
		a --; b --;
		graph[a].push_back(mp(w, b));
		invgraph[b].push_back(mp(w, a));
	}
	for (int i = 0; i < n; i ++){
		sort(graph[i].begin(), graph[i].end());
		sort(invgraph[i].begin(), invgraph[i].end());
	}

	deleted.resize(10, vector<vector<vector<bool> > >(10, vector<vector<bool> >(10, vector<bool>(10, false))));

	for (int i = 0; i < n; i ++){
		vector<int>posiciones(invgraph[i].size());

		for (int j = 0; j < invgraph[i].size(); j ++){
			pair<int, int> P = invgraph[i][j];
			int org = P.second;
			int w = P.first;
			int s = graph[org].size();
			int pos = 0;

			for (int l = 0; l < s; l ++){
				if (graph[org][l].first == w){
					pos = l;
				}
			}
			posiciones[j] = pos;
		}

		for (int j = 0; j < invgraph[i].size(); j ++){
			int org = invgraph[i][j].second;
			int w = invgraph[i][j].first;
			int s = graph[org].size();

			for (int j2 = 0; j2 < invgraph[i].size(); j2 ++){
				if (j != j2){
					int org2 = invgraph[i][j2].second;
					int w2 = invgraph[i][j2].first;
					int s2 = graph[org2].size();
					deleted[s][posiciones[j]][s2][posiciones[j2]] = 1;
				}
			}
		}
	}

	ll ans = 0LL;
	ans = backt(1);
	cout << ans << "\n";
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef long double ld;
#define mp make_pair
#define pb push_back
int limit;

bool deleted[10][10][10][10];
int indices[10];

ll backt(int i){
	if (i == limit + 1){
		return 1LL;
	}
	ll ans = 0LL;
	for (int j = 0; j < i; j ++){
		if (deleted[i][j][i][j]) continue;
		bool J = false;
		for (int k = 0; k + 1 < i; k ++) J = J | deleted[k + 1][indices[k]][i][j];
		if (J) continue;
		indices[i - 1] = j;
		ans += backt(i + 1);
	}
	return ans;
}

int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	for (int i = 0; i < 10; i ++)
		for (int j = 0; j < 10; j ++)
			for (int l = 0; l < 10; l ++)
				for (int q = 0; q < 10; q ++)
					deleted[i][j][l][q] = 0;
	int n, m, k;
	cin >> n >> m >> k;
	limit = k;
	vector<vector<pair<int, int> > >graph(n), invgraph(n);
	for (int i = 0; i < m; i ++){
		int a, b, w;
		cin >> a >> b >> w;
		a --; b --;
		graph[a].push_back(mp(w, b));
		invgraph[b].push_back(mp(w, a));
	}
	for (int i = 0; i < n; i ++){
		sort(graph[i].begin(), graph[i].end());
		sort(invgraph[i].begin(), invgraph[i].end());
	}

	for (int i = 0; i < n; i ++){
		vector<int>posiciones(invgraph[i].size());
		for (int j = 0; j < invgraph[i].size(); j ++){
			pair<int, int> P = invgraph[i][j];
			int org = P.second;
			int w = P.first;
			int s = graph[org].size();

			for (int l = 0; l < s; l ++)
				if (graph[org][l].first == w)
					posiciones[j] = l;
		}
		vector<pair<int, int> >S;
		vector<vector<bool> >Sp(10, vector<bool>(10, false));
		for (int j = 0; j < invgraph[i].size(); j ++){
			int org = invgraph[i][j].second;
			int s = graph[org].size();
			if (Sp[s][posiciones[j]]) deleted[s][posiciones[j]][s][posiciones[j]] = 1;
			else{
				Sp[s][posiciones[j]] = 1;
				S.push_back(mp(s, posiciones[j]));
			}
		}
		for (int j = 0; j + 1 < S.size(); j ++){
			for (int j2 = j + 1; j2 < S.size(); j2 ++){
				deleted[S[j].first][S[j].second][S[j2].first][S[j2].second] = 1;
				deleted[S[j2].first][S[j2].second][S[j].first][S[j].second] = 1;
			}
		}

	}

	ll ans = 0LL;
	ans = backt(1);
	cout << ans << "\n";
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef long double ld;
#define mp make_pair
#define pb push_back
int limit;

vector<vector<vector<vector<bool> > > >deleted;
vector<int>indices;

ll backt(int i){
	if (i == limit + 1){
		return 1LL;
	}
	ll ans = 0LL;
	for (int j = 0; j < i; j ++){
		if (deleted[i][j][i][j]) continue;
		bool J = false;
		for (int k = 0; k < indices.size(); k ++) J = J | deleted[k + 1][indices[k]][i][j];
		if (J) continue;

		indices.push_back(j);
		ans += backt(i + 1);
		indices.pop_back();
	}
	return ans;
}

int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	int n, m, k;
	cin >> n >> m >> k;
	limit = k;
	vector<vector<pair<int, int> > >graph(n), invgraph(n);
	for (int i = 0; i < m; i ++){
		int a, b, w;
		cin >> a >> b >> w;
		a --; b --;
		graph[a].push_back(mp(w, b));
		invgraph[b].push_back(mp(w, a));
	}
	for (int i = 0; i < n; i ++){
		sort(graph[i].begin(), graph[i].end());
		sort(invgraph[i].begin(), invgraph[i].end());
	}

	deleted.resize(10, vector<vector<vector<bool> > >(10, vector<vector<bool> >(10, vector<bool>(10, false))));

	for (int i = 0; i < n; i ++){
		vector<int>posiciones(invgraph[i].size());

		for (int j = 0; j < invgraph[i].size(); j ++){
			pair<int, int> P = invgraph[i][j];
			int org = P.second;
			int w = P.first;
			int s = graph[org].size();
			int pos = 0;

			for (int l = 0; l < s; l ++){
				if (graph[org][l].first == w){
					pos = l;
				}
			}
			posiciones[j] = pos;
		}

		for (int j = 0; j < invgraph[i].size(); j ++){
			int org = invgraph[i][j].second;
			int w = invgraph[i][j].first;
			int s = graph[org].size();

			for (int j2 = 0; j2 < invgraph[i].size(); j2 ++){
				if (j != j2){
					int org2 = invgraph[i][j2].second;
					int w2 = invgraph[i][j2].first;
					int s2 = graph[org2].size();
					deleted[s][posiciones[j]][s2][posiciones[j2]] = 1;
				}
			}
		}
	}

	ll ans = 0LL;
	ans = backt(1);
	cout << ans << "\n";
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef long double ld;
#define mp make_pair
#define pb push_back
int limit;

bool mat[10][10];
vector<vector<vector<vector<bool> > > >deleted;
vector<int>indices;

ll backt(int i){
	if (i == limit + 1){
		return 1LL;
	}
	ll ans = 0LL;
	vector<vector<bool> > aux(10, vector<bool>(10, false));
	for (int k = 0; k < 10; k ++){
		for (int k2 = 0; k2 < 10; k2 ++){
			aux[k][k2] = mat[k][k2];
		}
	}
	for (int j = 0; j < i; j ++){
		if (deleted[i][j][i][j]) continue;
		bool J = false;
		for (int k = 0; k < indices.size(); k ++){
			if (deleted[k + 1][indices[k]][i][j]) J = true;
		}
		if (J) continue;

		indices.push_back(j);
		ans += backt(i + 1);
		indices.pop_back();
	}
	return ans;
}

int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	for (int i = 0; i < 10; i ++){
		for (int j = 0; j < 10; j ++){
			mat[i][j] = false;
		}
	}
	int n, m, k;
	cin >> n >> m >> k;
	limit = k;
	vector<vector<pair<int, int> > >graph(n), invgraph(n);
	for (int i = 0; i < m; i ++){
		int a, b, w;
		cin >> a >> b >> w;
		a --; b --;
		graph[a].push_back(mp(w, b));
		invgraph[b].push_back(mp(w, a));
	}
	for (int i = 0; i < n; i ++){
		sort(graph[i].begin(), graph[i].end());
		sort(invgraph[i].begin(), invgraph[i].end());
	}

	deleted.resize(10, vector<vector<vector<bool> > >(10, vector<vector<bool> >(10, vector<bool>(10, false))));

	for (int i = 0; i < n; i ++){
		vector<int>posiciones(invgraph[i].size());

		for (int j = 0; j < invgraph[i].size(); j ++){
			pair<int, int> P = invgraph[i][j];
			int org = P.second;
			int w = P.first;
			int s = graph[org].size();
			int pos = 0;

			for (int l = 0; l < s; l ++){
				if (graph[org][l].first == w){
					pos = l;
				}
			}
			posiciones[j] = pos;
		}

		for (int j = 0; j < invgraph[i].size(); j ++){
			int org = invgraph[i][j].second;
			int w = invgraph[i][j].first;
			int s = graph[org].size();

			for (int j2 = 0; j2 < invgraph[i].size(); j2 ++){
				if (j != j2){
					int org2 = invgraph[i][j2].second;
					int w2 = invgraph[i][j2].first;
					int s2 = graph[org2].size();
					deleted[s][posiciones[j]][s2][posiciones[j2]] = 1;
				}
			}
		}
	}

	ll ans = 0LL;
	ans = backt(1);
	cout << ans << "\n";
}


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef long double ld;
#define mp make_pair
#define pb push_back
int limit;

bool deleted[10][10][10][10];
int indices[10];

ll backt(int i){
	if (i == limit + 1){
		return 1LL;
	}
	ll ans = 0LL;
	for (int j = 0; j < i; j ++){
		if (deleted[i][j][i][j]) continue;
		bool J = false;
		for (int k = 0; k + 1 < i; k ++) J = J | deleted[k + 1][indices[k]][i][j];
		if (J) continue;
		indices[i - 1] = j;
		ans += backt(i + 1);
	}
	return ans;
}

int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	for (int i = 0; i < 10; i ++){
		for (int j = 0; j < 10; j ++){
			for (int l = 0; l < 10; l ++){
				for (int q = 0; q < 10; q ++){
					deleted[i][j][l][q] = 0;
				}
			}
		}
	}
	int n, m, k;
	cin >> n >> m >> k;
	limit = k;
	vector<vector<pair<int, int> > >graph(n), invgraph(n);
	for (int i = 0; i < m; i ++){
		int a, b, w;
		cin >> a >> b >> w;
		a --; b --;
		graph[a].push_back(mp(w, b));
		invgraph[b].push_back(mp(w, a));
	}
	for (int i = 0; i < n; i ++){
		sort(graph[i].begin(), graph[i].end());
		sort(invgraph[i].begin(), invgraph[i].end());
	}

	for (int i = 0; i < n; i ++){
		vector<int>posiciones(invgraph[i].size());

		for (int j = 0; j < invgraph[i].size(); j ++){
			pair<int, int> P = invgraph[i][j];
			int org = P.second;
			int w = P.first;
			int s = graph[org].size();
			int pos = 0;

			for (int l = 0; l < s; l ++){
				if (graph[org][l].first == w){
					pos = l;
				}
			}
			posiciones[j] = pos;
		}

		for (int j = 0; j < invgraph[i].size(); j ++){
			int org = invgraph[i][j].second;
			int w = invgraph[i][j].first;
			int s = graph[org].size();

			for (int j2 = 0; j2 < invgraph[i].size(); j2 ++){
				if (j != j2){
					int org2 = invgraph[i][j2].second;
					int w2 = invgraph[i][j2].first;
					int s2 = graph[org2].size();
					deleted[s][posiciones[j]][s2][posiciones[j2]] = 1;
				}
			}
		}
	}

	ll ans = 0LL;
	ans = backt(1);
	cout << ans << "\n";
}


#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 500050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
int n, m, k;
struct edge
{
    int v, w;
    edge() {}
    edge(int _v, int _w) : v(_v), w(_w) {}
    bool operator<(const edge &x) const
    {
        return w < x.w;
    }
};
vector<edge> e[N];
vector<int> p[11];
ll ans;
bitset<200001> vis[10][10], now, all, q[10];
void dfs(int step)
{
    if (step == k + 1)
    {
        if (q[step] == all)
            ans++;
        return;
    }
    for (int c = 1; c <= step; ++c)
    {
        if (!(q[step] & vis[step][c]).none())
            continue;
        q[step+1] =q[step] |vis[step][c];
        dfs(step + 1);
    }
}

inline void solve()
{
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; ++i)
        all[i] = 1;
    for (int i = 1; i <= m; ++i)
    {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        x--, y--;
        e[x].push_back(edge(y, w));
    }
    for (int i = 0; i < n; ++i)
        vecupsort(e[i]);
    for (int i = 0; i < n; ++i)
        p[(int)e[i].size()].push_back(i);
    for (int i = 1; i <= k; ++i)
    {
        for (int c = 0; c < i; ++c)
        {
            for (auto u : p[i])
                vis[i][c + 1][(int)e[u][c].v] = 1;
        }
    }
    dfs(1);
    printf("%lld\n", ans);
}

int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
        solve();
    TIME__END = clock();
    program_end();
    return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 500050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
int n, m, k;
struct edge
{
    int v, w;
    edge() {}
    edge(int _v, int _w) : v(_v), w(_w) {}
    bool operator<(const edge &x) const
    {
        return w < x.w;
    }
};
vector<edge> e[N];
vector<int> p[11];
ll ans;
bitset<200001> vis[10][10], now, all, q[10];
vector<pii> cant[10][10];
int nowcant[10][10];
int lst[10];
bool verycant[10][10];

void dfs(int step)
{
    if (step == k + 1)
    {
        ans++;
        return;
    }
    for (int c = 1; c <= step; ++c)
    {
        if (nowcant[step][c] || verycant[step][c])
            continue; //lst[step]=c;
        for (auto j : cant[step][c])
            ++nowcant[j.first][j.second];
        dfs(step + 1);
        for (auto j : cant[step][c])
            nowcant[j.first][j.second]--;
    }
}

inline void solve()
{
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; ++i)
        all[i] = 1;
    for (int i = 1; i <= m; ++i)
    {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        x--, y--;
        e[x].push_back(edge(y, w));
    }
    for (int i = 0; i < n; ++i)
        vecupsort(e[i]);
    for (int i = 0; i < n; ++i)
        p[(int)e[i].size()].push_back(i);
    for (int i = 1; i <= k; ++i)
    {
        for (int c = 0; c < i; ++c)
        {
            for (auto u : p[i])
            {
                if (vis[i][c + 1][(int)e[u][c].v])
                    verycant[i][c + 1] = 1;
                vis[i][c + 1][(int)e[u][c].v] = 1;
            }
        }
    }
    for (int i = 1; i <= k; ++i)
    {
        for (int j = i + 1; j <= k; ++j)
        {
            for (int c1 = 1; c1 <= i; ++c1)
                for (int c2 = 1; c2 <= j; ++c2)
                {
                    if ((vis[i][c1] & vis[j][c2]).count())
                        cant[i][c1].push_back(mp(j, c2)), cant[j][c2].push_back(mp(i, c1));
                }
        }
    }
    dfs(1);
    printf("%lld\n", ans);
}

int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
        solve();
    TIME__END = clock();
    program_end();
    return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 500050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
int n, m, k;
struct edge
{
    int v, w;
    edge() {}
    edge(int _v, int _w) : v(_v), w(_w) {}
    bool operator<(const edge &x) const
    {
        return w < x.w;
    }
};
vector<edge> e[N];
vector<int> p[11];
ll ans;
bitset<200001> vis[10][10], now, all;
void dfs(int step)
{
    if (step == k + 1)
    {
        if (now == all)
            ans++;
        return;
    }
    for (int c = 1; c <= step; ++c)
    {
        if (!(now & vis[step][c]).none())
            continue;
        now ^= vis[step][c];
        dfs(step + 1);
        now ^= vis[step][c];
    }
}

inline void solve()
{
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; ++i)
        all[i] = 1;
    for (int i = 1; i <= m; ++i)
    {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        x--, y--;
        e[x].push_back(edge(y, w));
    }
    for (int i = 0; i < n; ++i)
        vecupsort(e[i]);
    for (int i = 0; i < n; ++i)
        p[(int)e[i].size()].push_back(i);
    for (int i = 1; i <= k; ++i)
    {
        for (int c = 0; c < i; ++c)
        {
            for (auto u : p[i])
                vis[i][c + 1][(int)e[u][c].v] = 1;
        }
    }
    dfs(1);
    printf("%lld\n", ans);
}

int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
        solve();
    TIME__END = clock();
    program_end();
    return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 500050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
int n, m, k;
struct edge
{
    int v, w;
    edge() {}
    edge(int _v, int _w) : v(_v), w(_w) {}
    bool operator<(const edge &x) const
    {
        return w < x.w;
    }
};
vector<edge> e[N];
vector<int> p[11];
ll ans;
bitset<200002> vis[10][10], now, all;
void dfs(int step)
{
    if (step == k + 1)
    {
        if (now == all)
            ans++;
        return;
    }
    for (int c = 1; c <= step; ++c)
    {
        if (!(now & vis[step][c]).none())
            continue;
        bitset<200002> bnow = now;
        now |= vis[step][c];
        dfs(step + 1);
        now = bnow;
    }
}

inline void solve()
{
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; ++i)
        all[i] = 1;
    for (int i = 1; i <= m; ++i)
    {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        x--, y--;
        e[x].push_back(edge(y, w));
    }
    for (int i = 0; i < n; ++i)
        vecupsort(e[i]);
    for (int i = 0; i < n; ++i)
        p[(int)e[i].size()].push_back(i);
    for (int i = 1; i <= k; ++i)
    {
        for (int c = 0; c < i; ++c)
        {
            for (auto u : p[i])
                vis[i][c + 1][(int)e[u][c].v] = 1;
        }
    }
    dfs(1);
    printf("%lld\n", ans);
}

int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
        solve();
    TIME__END = clock();
    program_end();
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define rep(i,a,b) for(auto i=(a); i<(b); ++i)
#define trav(a,x) for(auto& a: x)
#define all(x) begin(x),end(x)
#define sz(x) (int)size(x)
#define PB push_back
using ll = long long;
using ld = long double;
using pii = pair<int,int>;
using vi = vector<int>;

struct edge{int to, w;};
using graph = vector<vector<edge>>;

auto getindex(const pii& i_deg, int k) {
  return (i_deg.second - 1) * k + i_deg.first;
}

int backtrack(int deg, int k, auto& used, const auto& conflict) {
  assert(sz(used) < deg);
  if (deg > k) {
    return 1;
  }
  auto ways = 0;
  rep(i, 0, deg) {
    auto ind = getindex({i, deg}, k);
    if (conflict[ind][ind]) continue;
    if (!all_of(all(used), [&](int j){return !conflict[ind][j];})) continue;

    used.PB(ind);
    ways += backtrack(deg + 1, k, used, conflict);
    used.pop_back();
  }
  return ways;
}

int main() {
  cin.sync_with_stdio(0); cin.tie(0);
  cin.exceptions(cin.failbit);

  int n, m, k;
  cin >> n >> m >> k;
  graph g(n);
  rep(it, 0, m) {
    int u, v, w;
    cin >> u >> v >> w;
    --u; --v;
    g[u].PB({v, w});
  }
  vector<vector<pii>> t(n); // coordinate compressed transpose
  rep(i, 0, n) {
    sort(all(g[i]), [](const auto& e1, const auto& e2){return e1.w < e2.w;});
    auto deg = sz(g[i]);
    rep(d, 0, deg) {
      auto e = g[i][d];
      t[e.to].PB({d, deg});
    }
  }
  auto nn = (k + 1) * (k + 1);
  auto conflict = vector(nn, vi(nn));
  rep(i, 0, n) {
    rep(it1, 0, sz(t[i])) {
      auto ind = getindex(t[i][it1], k);
      rep(it2, it1 + 1, sz(t[i])) {
	auto ind2 = getindex(t[i][it2], k);
	conflict[ind][ind2] = conflict[ind2][ind] = true;
      }
    }
  }
  vi used;
  auto sol = backtrack(1, k, used, conflict);
  cout << sol << '\n';
}


#include <bits/stdc++.h>
using namespace std;

#define rep(i,a,b) for(auto i=(a); i<(b); ++i)
#define trav(a,x) for(auto& a: x)
#define all(x) begin(x),end(x)
#define sz(x) (int)size(x)
#define PB push_back
using ll = long long;
using ld = long double;
using pii = pair<int,int>;
using vi = vector<int>;

struct edge{int to, w;};
using graph = vector<vector<edge>>;

auto getindex(const pii& i_deg, int k) {
  return (i_deg.second - 1) * k + i_deg.first;
}

int backtrack(int deg, int k, auto& used, const auto& conflict) {
  assert(sz(used) < deg);
  if (deg > k) {
    return 1;
  }
  auto ways = 0;
  rep(i, 0, deg) {
    auto ind = getindex({i, deg}, k);
    if (conflict[ind][ind]) continue;
    if (!all_of(all(used), [&](int j){return !conflict[ind][j];})) continue;

    used.PB(ind);
    ways += backtrack(deg + 1, k, used, conflict);
    used.pop_back();
  }
  return ways;
}

int main() {
  cin.sync_with_stdio(0); cin.tie(0);
  cin.exceptions(cin.failbit);

  int n, m, k;
  cin >> n >> m >> k;
  graph g(n);
  rep(it, 0, m) {
    int u, v, w;
    cin >> u >> v >> w;
    --u; --v;
    g[u].PB({v, w});
  }
  vector<vector<pii>> t(n); // coordinate compressed transpose
  rep(i, 0, n) {
    sort(all(g[i]), [](const auto& e1, const auto& e2){return e1.w < e2.w;});
    auto deg = sz(g[i]);
    rep(d, 0, deg) {
      auto e = g[i][d];
      t[e.to].PB({d, deg});
    }
  }
  auto nn = (k + 1) * (k + 1);
  auto conflict = vector(nn, vi(nn));
  rep(i, 0, n) {
    sort(all(t[i]));
    rep(it, 0, sz(t[i]) - 1) {
      if (t[i][it] == t[i][it + 1]) {
	auto ind = getindex(t[i][it], k);
	conflict[ind][ind] = true;
      }
    }
    t[i].erase(unique(all(t[i])), end(t[i]));
    rep(it1, 0, sz(t[i])) {
      auto ind = getindex(t[i][it1], k);
      rep(it2, it1 + 1, sz(t[i])) {
	auto ind2 = getindex(t[i][it2], k);
	conflict[ind][ind2] = conflict[ind2][ind] = true;
      }
    }
  }
  vi used;
  auto sol = backtrack(1, k, used, conflict);
  cout << sol << '\n';
}


#include <bits/stdc++.h>
using namespace std;

#define rep(i,a,b) for(auto i=(a); i<(b); ++i)
#define trav(a,x) for(auto& a: x)
#define all(x) begin(x),end(x)
#define sz(x) (int)size(x)
#define PB push_back
using ll = long long;
using ld = long double;
using pii = pair<int,int>;
using vi = vector<int>;

struct edge{int to, w;};
using graph = vector<vector<edge>>;

auto getindex(pii i_deg, int k) {
  return (i_deg.second - 1) * k + i_deg.first;
}

int backtrack(int deg, int k, int n, auto& used, auto& conflict, const auto& freq, int nodes_into = 0) {
  if (deg > k) {
    assert(nodes_into == n);
    return 1;
  }
  auto ways = 0;
  rep(i, 0, deg) {
    auto ind = getindex({i, deg}, k);

    bool good = !conflict[ind][ind];
    trav(j, used) good &= !conflict[ind][j];
    if (!good) continue;

    used.PB(ind);
    ways += backtrack(deg + 1, k, n, used, conflict, freq, nodes_into + freq[ind]);
    used.pop_back();
  }
  return ways;
}

int main() {
  cin.sync_with_stdio(0); cin.tie(0);
  cin.exceptions(cin.failbit);

  int n, m, k;
  cin >> n >> m >> k;
  graph g(n);
  rep(it, 0, m) {
    int u, v, w;
    cin >> u >> v >> w;
    --u; --v;
    g[u].PB({v, w});
  }
  vector<vector<pii>> t(n); // coordinate compressed transpose
  rep(i, 0, n) {
    sort(all(g[i]), [](const auto& e1, const auto& e2){return e1.w < e2.w;});
    auto deg = sz(g[i]);
    rep(d, 0, deg) {
      auto e = g[i][d];
      t[e.to].PB({d, deg});
    }
  }
  auto nn = (k + 1) * (k + 1);
  auto conflict = vector(nn, vi(nn));
  vi freq(nn);
  rep(i, 0, n) {
    rep(it1, 0, sz(t[i])) {
      auto ind = getindex(t[i][it1], k);
      rep(it2, it1 + 1, sz(t[i])) {
	auto ind2 = getindex(t[i][it2], k);
	conflict[ind][ind2] = conflict[ind2][ind] = true;
      }
      freq[ind]++;
    }
  }
  vi used;
  auto sol = backtrack(1, k, n, used, conflict, freq);
  cout << sol << '\n';
}