加强版过了,本题没过
查看原帖
加强版过了,本题没过
792364
hzx198楼主2024/10/24 21:38

rt

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
constexpr ll N = 4e5 + 5;

// 手写哈希函数 (和+平方和)
ll make2(ll a, ll b) { return a * a + b * b + a + b; }
ll make3(ll a, ll b, ll c) { return make2(a, b) + c * c + c; }
ll make4(ll a, ll b, ll c, ll d) { return make3(a, b, c) + d * d + d; }

// 三元组
struct node {
  ll u, v, w;
  // 字典序
  friend bool operator<(const node &a, const node &b) {
    if (a.u != b.u) return a.u < b.u;
    if (a.v != b.v) return a.v < b.v;
    return a.w < b.w;
  }
} a[N];

// mp: 三元组标记, mp4: 四元组标记
unordered_map<ll, bool> mp, mp4;

// 判断四元组 a,b,c,d 是否满足题目要求
bool judge(ll a, ll b, ll c, ll d) {
  if (!(a < b && b < c && c < d)) return 0;
  if (mp[make3(a, b, c)] == 0) return 0;
  if (mp[make3(a, b, d)] == 0) return 0;
  if (mp[make3(a, c, d)] == 0) return 0;
  if (mp[make3(b, c, d)] == 0) return 0;
  return 1;
}

// 从 二元组(三元组的前两个数) 到 三元组下标 的映射, st 表示开始下标, ed 表示结束下标
unordered_map<ll, ll> st, ed;

ll n, m, ans;

int main(void) {
  ios::sync_with_stdio(0), cin.tie(nullptr);

  cin >> n >> m;
  for (ll i = 1, u, v, w; i <= m; i++) {
    cin >> u >> v >> w;
    mp[make3(u, v, w)] = 1;
    a[i] = {u, v, w};
  }

  sort(a + 1, a + 1 + m);

  // 把每个三元组的前两个数构成的二元组的下标范围求出来, 方便后续查找
  for (ll i = 1; i <= m; i++) {
    ll t = make2(a[i].u, a[i].v);
    if (st[t] == 0) st[t] = i;
    ed[t] = i;
  }

  // 枚举三元组 (u,v,w)
  for (ll i = 1; i <= m; i++) {
    ll tc = make2(a[i].u, a[i].v); // 三元组的前两个数 (u,v)

    ll ta = make2(a[i].v, a[i].w); // 三元组的后两个数 (v,w)
    if (st[ta] == 0) continue; // (v,w) 不存在直接跳过

    ll tb = make2(a[i].u, a[i].w); // 三元组的首尾两个数 (u,w)
    if (st[tb] == 0) continue; // (u,w) 不存在直接跳过

    ll flag = tc; // 找范围最小的那一段
    if (ed[flag] - st[flag] > ed[ta] - st[ta]) flag = ta;
    if (ed[flag] - st[flag] > ed[tb] - st[tb]) flag = tb;

    // 枚举范围最小的那一段
    for (ll j = st[flag]; j <= ed[flag]; j++) {
      if (flag == tc && i == j) continue; // 最小的那一段就是 (u,v) 即三元组本身所在段, 需要跳过本身
      if (a[j].w <= a[i].w) continue; // 保证四元组递增
      if (judge(a[i].u, a[i].v, a[i].w, a[j].w)) {
//        // 去重, 统计
//        if (!mp4[make4(a[i].u, a[i].v, a[i].w, a[j].w)]) {
//          mp4[make4(a[i].u, a[i].v, a[i].w, a[j].w)] = 1;
          ans++;
//        }
      }
    }
  }

  printf("%lld\n", ans);
  return 0;
}
2024/10/24 21:38
加载中...