HDU-ACM 2024 Day2

hztmax0發表於2024-08-11

T1004 a*b problem(HDU 7448)

不會。

T1005 小塔的養成遊戲之夢(HDU 7449)

不會。

T1009 強攻計策(HDU 7453)

容易發現初始速度是多少對答案沒有影響,所以我們預設初始速度為 \(0\)。題意相當於在平面直角座標系上(橫軸為時間,縱軸為速度),有一個目標高度,維護一條儘量接近目標的直線,但斜率只能是 \(-1/0/1\),要支援一段區間目標 \(+1\),求直線下方面積。

將一次區間 \(+1\) 拆成一段字尾 \(+1\) 和一段字尾 \(-1\)。注意到一次字尾 \(+1/-1\) 時至多隻有一個位置發生向上/向下翻折,在這個位置前與目標的相對高度 \(-1/+1\),之後相對高度不變,那麼此時面積的變化量容易用這個位置表示,我們現在的任務就是快速找到這個位置。

具體而言,設 \(h_i\) 表示直線在 \(x = i\) 處的相對高度,手玩容易發現當區間 \(+1\) 時,我們要找第一個 \(0/-1\),區間 \(-1\) 時,我們要找第一個 \(0/1\)

現在我們要維護一個資料結構,支援區間 \(+1/-1\),區間找第一個 \(-1/0/1\),考慮分塊,塊內維護排序陣列,修改時整塊打標記,散塊歸併重構,詢問時散塊暴力,整塊二分即可,平衡塊長,時間複雜度 \(O(n \sqrt {n \log n})\),常數較小。

Code
#include <iostream>
#include <cmath>
#include <numeric>
#include <algorithm>
#include <vector>

using namespace std;
using LL = long long;

const int N = 1e5 + 5; 
const int Mod = 1e9 + 7, Inv = (Mod + 1) / 2;

int n, m;
LL ans;

namespace Block {
  int len, cnt;
  int a[N], b[N], tag[N], bl[N], L[N], R[N];

  void build () {
    len = sqrt(n) * 0.4; 
    for (int i = 0; i <= n; ++i) {
      bl[i] = i / len + 1;
    }
    cnt = bl[n];
    R[0] = -1;
    for (int i = 1; i <= cnt; ++i) {
      L[i] = R[i - 1] + 1;
      R[i] = min(n, L[i] + len - 1);
    }
    fill(a, a + n + 1, 0);
    iota(b, b + n + 1, 0);
    fill(tag, tag + cnt + 1, 0);
  }

  int first_val (int x, int y) {
    for (int i = x; i <= R[bl[x]]; ++i) {
      if (a[i] == y - tag[bl[x]]) {
        return i;
      }
    }
    for (int i = bl[x] + 1; i <= cnt; ++i) {
      if (a[b[R[i]]] < y - tag[i] || a[b[L[i]]] > y - tag[i]) continue;
      auto cmp = [&](int i, int j) -> bool {
        return a[i] < j;
      };
      auto it = lower_bound(b + L[i], b + R[i] + 1, y - tag[i], cmp);
      if (it != b + R[i] + 1 && a[*it] == y - tag[i]) return *it;
    }
    return n + 1;
  }

  int tmpa[N][2];
  int al[2];

  void add (int l, int r, int x) {
    r = min(r, n);
    auto rebuild = [&](int l, int r, int gl, int gr) -> void {
      al[0] = 0, al[1] = 0; 
      for (int i = l; i <= r; ++i) {
        int o = b[i] >= gl && b[i] <= gr;
        tmpa[++al[o]][o] = b[i];
      }
      int p = l;
      auto cmp = [&](int i, int j) -> bool {
        return a[i] < a[j] || a[i] == a[j] && i < j;
      };
      for (int cur[2] = {1, 1}; cur[0] != al[0] + 1 || cur[1] != al[1] + 1; ) {
        if (cur[0] != al[0] + 1 && (cur[1] == al[1] + 1 || cmp(tmpa[cur[0]][0], tmpa[cur[1]][1]))) {
          b[p++] = tmpa[cur[0]][0], ++cur[0];
        }  
        else {
          b[p++] = tmpa[cur[1]][1], ++cur[1];
        }      
      }
    };
    if (bl[l] == bl[r]) {
      for (int i = l; i <= r; ++i) {
        a[i] += x;
      }
      rebuild(L[bl[l]], R[bl[l]], l, r);
    } 
    else {
      for (int i = l; i <= R[bl[l]]; ++i) {
        a[i] += x;
      }
      for (int i = L[bl[r]]; i <= r; ++i) {
        a[i] += x;
      } 
      rebuild(L[bl[l]], R[bl[l]], l, R[bl[l]]);
      rebuild(L[bl[r]], R[bl[r]], L[bl[r]], r);
      for (int i = bl[l] + 1; i <= bl[r] - 1; ++i) {
        tag[i] += x;
      }
    }
  }
}

void suf_add (int x) {
  int pos = min(Block::first_val(x, 0), Block::first_val(x, 1));
  ans += max(0, (n - pos) * 2 - 1);
  Block::add(x, pos, -1);
}

void suf_minus (int x) {
  int pos = min(Block::first_val(x, 0), Block::first_val(x, -1));
  ans -= max(0, (n - pos) * 2 - 1);
  Block::add(x, pos, 1);
}

int main () {
  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  int T;
  cin >> T;
  while (T--) {
    cin >> n >> m;
    Block::build(), ans = 0; 
    for (int i = 1, l, r; i <= m; ++i) {
      cin >> l >> r; 
      suf_add(l), suf_minus(r);
      cout << ans % Mod * Inv % Mod << '\n';
    }
  }
  return 0; 
}

T1012 圖計算(HDU 7456)

考慮對於每一張圖分別維護並查集,我們使用啟發式合併,這樣可以保證每個結點的 \(fa\) 就是它的最高階祖先,對於每一個結點,為它在所有圖中的 \(fa\) 序列雜湊即可。

Code
#include <iostream>
#include <vector>
#include <tuple>
#include <unordered_map>

using namespace std;
using LL = long long;
using Tp = tuple<int, int, int>;

const int N = 5e4 + 5, M = 105; 

int n, m, d, q;

struct Hash_Arr {
  int len; 

  struct Hash {
    int mod, base, len;
    int pw[M], now;

    void init (int mod_, int base_, int len_) {
      mod = mod_, base = base_, now = 0, len = len_;
      pw[0] = 1; 
      for (int i = 1; i <= len; ++i) {
        pw[i] = 1ll * pw[i - 1] * base % mod;
      }
    }

    void add (int x, int y) { now = (now + 1ll * (mod + y) * pw[x]) % mod; }
  } ha[3];

  void init (int len_) {
    len = len_;
    ha[0].init(1000000007, 1000000009, len);
    ha[1].init(1000000021, 1000000033, len);
    ha[2].init(1000000087, 1000000093, len);
  }

  void add (int x, int y) {
    ha[0].add(x, y);
    ha[1].add(x, y);
    ha[2].add(x, y);
  }

  Tp get_val () { return make_tuple(ha[0].now, ha[1].now, ha[2].now); }
} h[N];

struct tHash {
  const int tB = 998244353, tP = tB * tB;

  int operator() (Tp x) const {
    return get<0>(x) + get<1>(x) * tB * get<2>(x) * tP;
  }
};

unordered_map<Tp, int, tHash> p; 
LL ans; 

void add (Tp x) {
  int v = p[x]++; 
  ans += v; 
}  

void remove (Tp x) {
  int v = --p[x];
  ans -= v;
}

struct U {
  int fa[N], id;
  vector<int> vec[N];

  void init (int id_) {
    id = id_;
    fill(vec + 1, vec + n + 1, vector<int>());
    for (int i = 1; i <= n; ++i) {
      vec[i].push_back(i);
      fa[i] = i; 
      h[i].add(id, i);
    }
  }

  void unite (int x, int y) {
    x = fa[x], y = fa[y];
    if (x == y) return; 
    if (vec[x].size() < vec[y].size()) swap(x, y);
    for (auto v : vec[y]) {
      vec[x].push_back(v);
      remove(h[v].get_val());
      h[v].add(id, x - fa[v]);
      add(h[v].get_val());
      fa[v] = x;
    }
    vec[y].clear();
  }
} uf[M]; 

int main () {
  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  int T;
  cin >> T;
  while (T--) {
    cin >> n >> m >> d >> q;
    for (int i = 1; i <= n; ++i) {
      h[i].init(d + 1);
    }
    for (int i = 1; i <= d + 1; ++i) {
      uf[i].init(i);
    } 
    p.clear(), ans = 0; 
    for (int i = 1; i <= n; ++i) {
      add(h[i].get_val());
    } 
    for (int i = 1, u, v; i <= m; ++i) {
      cin >> u >> v;
      for (int j = 1; j <= d + 1; ++j) {
        uf[j].unite(u, v);
      }
    }
    for (int i = 1, u, v, w; i <= q; ++i) {
      cin >> u >> v >> w;
      uf[w].unite(u, v);
      cout << ans << '\n';
    }
  }
  return 0;
}

相關文章