2020CCPC長春 K - Ragdoll(啟發式合並)


題意:初始有 \(n\) 個節點 \(1\)\(n\),權值分別為 \(a_1...a_n\)
有三種操作,\(1.\)新建標號為 \(x\) 的節點,權值為 \(y\)\(2.\) 合並標號為 \(x\)\(y\) 所在的樹(集合)。\(3.\) 將標號為 \(x\) 的節點權值修改成 \(y\)。每次操作后詢問 \(\gcd(a_i, a_j) = a_i \oplus a_j\) 的對數,並且要求 \(i,j\) 在同一樹中。

對於 \(a_i\) 來說,不同的 \(\gcd\) 取值等於約數個數,考慮枚舉 \(a_i\) 的約數並判斷這個約數有沒有貢獻。具體的,
對於 \(a_i\) 的約數 \(x\),我們想找到一個值 \(y\) 使得 \(\gcd(a_i,x) = x = a_i \oplus y\),即 \(y=a_i \oplus x\),之后判斷 \(\gcd(a_i,y)\)\(x\) 是否相等,進而得到 \(a_i\) 的一組解。

然后 \(\mathcal{O}(n\log^2 n)\) 的預處理貢獻和 \(\mathcal{O}(n\log n)\) 的啟發式合並就可以ac了,合並的時候大概有一個幾十的常數。

#include <bits/stdc++.h>
using namespace std;
              
#define fi first
#define se second 
#define mp make_pair
#define pb push_back
#define debug(x) cerr << #x << " is " << x << '\n';
 
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long ull;
           
const int N = 5e5 + 5, M = 2e5, P = 1e9 + 7, INF = 0X3F3F3F3F;
const ull D = 743, mo1 = 966335533, mo2 = 966331133;

int n, q, u, v, a[N];
int fa[N], sz[N];
LL ans;
std::vector<int> g[N];
unordered_map<int, LL> dsu[N];

int find(int x) {
  return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  for (int i = 1, y; i <= M; i++) {
    for (int j = i + i; j <= M; j += i) {
      y = (j ^ i);
      if (i == __gcd(j, y)) {
        g[j].pb(y);
      }
    }
  }
  cin >> n >> q;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
    dsu[i][a[i]]++;
  }
  for (int i = 1; i <= n + q; i++) {
    fa[i] = i;
    sz[i] = 1;
  }
  for (int i = 1, op, x, y; i <= q; i++) {
    cin >> op >> x >> y;
    if (op == 1) {
      a[x] = y;
      dsu[x][y]++;
      cout << ans << '\n';
    } else if (op == 2) {
      u = find(x), v = find(y);
      if (u != v) {
        if (sz[u] > sz[v]) swap(u, v);
        for (auto &it : dsu[u]) {
          for (auto &it1 : g[it.fi]) {
            if (dsu[v].count(it1)) ans += it.se * dsu[v][it1];
          }
        }
        for (auto &it : dsu[u]) dsu[v][it.fi] += it.se;
        dsu[u].clear();
        fa[u] = v, sz[v] += sz[u];
      }
      cout << ans << '\n';
    } else {
      u = find(x);
      for (auto &it :g[a[x]]) {
        if (dsu[u].count(it)) ans -= dsu[u][it];
      }
      dsu[u][a[x]]--;
      a[x] = y;
      for (auto &it :g[a[x]]) {
        if (dsu[u].count(it)) ans += dsu[u][it];
      }
      dsu[u][a[x]]++;
      cout << ans << '\n';
    }
  }
  return 0;  
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM