UER #1

A. 猜数

题目描述

给定 \(g,l\),满足 \(gl=ab\),且 \(a,b\)\(g\) 的倍数。求 \(a+b\) 的最小/大值。

思路

根据积一定差小和小,最小值为 \(2\sqrt {g\cdot l}\),最大值为 \(g+l\)

时空复杂度均为 \(O(1)\)

代码

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

int t;
ll a, b;

void Solve() {
  cin >> a >> b;
  cout << 2ll * a * (ll)sqrt(b / a) << " " << a + b << "\n";
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  for(cin >> t; t--; Solve()) {
  }
  return 0;
}

C. DZY Loves Graph

题目描述

\(N\) 个点,\(M\) 次操作。对于第 \(i\) 次操作有:

  • \(a,b\) 之间建一条边权为 \(i\) 的边。
  • 撤销最新建的 \(k\) 条边。
  • 撤销 \(i-1\) 次操作,保证 \(i-1\) 次操作不为此操作。

请在每次操作后求出最小生成树的边权之和。

思路

我们可以用栈记录当前仍然有效的 1 操作和当时的生成树边权之和和生成树的边的数量。但为了避免这种情况:

Add
Add
...
Delete
Return
Delete
Return
...

我们要记录一个 \(k\),表示当前有 \(k\) 个未处理的撤销。在有新的 Add 操作之前,我们可以直接访问之前的答案。如果有 Add,那么就一个一个处理撤销。因为此时已经不可能再去 Return 之前的 Delete 了。使用可撤销化并查集。

空间复杂度 \(O(N+M)\),时间复杂度 \(O(M\log N)\)

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;

const int MAXM = 500001, MAXN = 300001;

struct query {
  string op;
  int a, b;
}a[MAXM];

int n, m, f[MAXN], sz[MAXN], k, cnt[MAXM], stk[MAXN], top;
ll sum[MAXM];
vector<pii> edge;

int getfa(int u) {
  return (f[u] == u ? u : getfa(f[u]));
}

bool Merge(int u, int v) {
  u = getfa(u), v = getfa(v);
  if(u != v) {
    if(sz[u] > sz[v]) {
      swap(u, v);
    }
    f[u] = v, sz[v] += sz[u];
    edge.emplace_back(u, v);
    return 1;
  }else {
    edge.emplace_back(0, 0);
    return 0;
  }
}

void Cancal() {
  auto [u, v] = edge.back();
  edge.pop_back();
  f[u] = u, sz[v] -= sz[u];
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> m;
  iota(f + 1, f + n + 1, 1);
  fill(sz + 1, sz + n + 1, 1);
  cnt[0] = n, sum[0] = 0;
  for(int i = 1; i <= m; ++i) {
    cin >> a[i].op;
    if(a[i].op == "Add") {
      cin >> a[i].a >> a[i].b;
      for(; k; k--, top--) {
        Cancal();
      }
      cnt[i] = cnt[stk[top]], sum[i] = sum[stk[top]];
      if(Merge(a[i].a, a[i].b)) {
        cnt[i]--;
        sum[i] += i;
      }
      stk[++top] = i;
      cout << (cnt[i] != 1 ? 0 : sum[i]) << "\n";
    }else if(a[i].op == "Delete") {
      cin >> a[i].a;
      k += a[i].a;
      cout << (cnt[stk[top - k]] != 1 ? 0 : sum[stk[top - k]]) << "\n";
    }else {
      if(a[i - 1].op == "Add") {
        k++;
        cout << (cnt[stk[top - k]] != 1 ? 0 : sum[stk[top - k]]) << "\n";
      }else {
        k -= a[i - 1].a;
        cout << (cnt[stk[top - k]] != 1 ? 0 : sum[stk[top - k]]) << "\n";
      }
    }
  }
  return 0;
}
posted @ 2024-10-02 21:00  Yaosicheng124  阅读(1)  评论(0编辑  收藏  举报