CodeForces Gym 102056 简要题解

Exotic … Ancient City

注意到值域很小,所以可以对每种 w w w 数只考虑 ≤ w \le w w 的边的连通块个数。维护一个大小为 2 n 2n 2n 的并查集,表示第 i i i 列和第 i + 1 i+1 i+1 列的连通性。考虑右移一列并查集的变化,如果在之前的并查集合并了集合 u + n , v + n u+n, v+n u+n,v+n ,那么在新的并查集上 u u u v v v 会变得连通。如果它们已经连通了,这条边就没用了;否则它们可能新增连通性,对后面有影响,以此类推即可。

#include 

using namespace std;

const int MAX = 30;

class dsu {
 public:
  vector<int> p;
  int n;

  dsu(int n): n(n) {
    p.resize(n);
    for (int i = 0; i < n; ++i) {
      p[i] = i;
    }
  }

  inline int find(int x) {
    while (x != p[x]) {
      x = p[x] = p[p[x]];
    }
    return x;
  }

  inline bool unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) {
      return false;
    } else {
      p[x] = y;
      return true;
    }
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m, q;
  cin >> n >> m >> q;
  vector<vector<pair<int, int>>> edges(MAX);
  while (q--) {
    int from, to, cost;
    cin >> from >> to >> cost;
    --from;
    --to;
    for (int i = cost; i < MAX; ++i) {
      edges[i].emplace_back(from, to);
    }
  }
  vector<long long> ans(m);
  for (int w = 0; w < MAX; ++w) {
    dsu p(n * 2);
    vector<long long> tag(m);
    vector<pair<int, int>> useful;
    for (auto e : edges[w]) {
      int x = p.find(e.first), y = p.find(e.second + n);
      if (x > y) {
        swap(x, y);
      }
      if (p.unite(x, y)) {
        ++tag[0];
        if (x >= n && y >= n) {
          useful.emplace_back(x - n, y - n);
        }
      }
    }
    for (int i = 1; i < m && !useful.empty(); ++i) {
      vector<pair<int, int>> new_useful;
      for (auto e : useful) {
        int x = p.find(e.first), y = p.find(e.second);
        if (x > y) {
          swap(x, y);
        }
        if (p.unite(x, y)) {
          if (x >= n && y >= n) {
            new_useful.emplace_back(x - n, y - n);
          }
        } else {
          --tag[i];
        }
      }
      swap(useful, new_useful);
    }
    for (int i = 1; i < m; ++i) {
      tag[i] += tag[i - 1];
    }
    for (int i = 1; i < m; ++i) {
      tag[i] += tag[i - 1];
    }
    for (int i = 0; i < m; ++i) {
      ans[i] += (long long) n * (i + 2) - 1 - tag[i];
    }
  }
  for (int i = 0; i < m; ++i) {
    cout << ans[i] << "\n";
  }
  return 0;
}

Mysterious … Host

考虑一个排列,用尽量少的段去覆盖它,分两种情况讨论:

  • 段数 ≥ 3 \ge 3 3 :划分方案是唯一的,连续段要么是整个排列要么在每段内部。其中段数为 3 3 3 无法构造,为 4 4 4 及以上可以构造。
  • 段数 = 2 =2 =2 :不妨假设 1 1 1 n n n 前面。如果长度为 i i i 的前缀正好是 [ 1 , i ] [1,i] [1,i] 的排列,那么划开 i i i i + 1 i+1 i+1 。连续段要么是若干个整段,要么是段内部。

所以 f ( n ) = ∑ k ≥ 2 ∏ ∑ i = 1 k a i = n f ( a i ) + ∑ k ≥ 4 ∏ ∑ i = 1 k a i = n f ( a i ) f(n) = \sum_{k\ge 2} \prod_{\sum_{i=1}^k a_i = n} f(a_i) + \sum_{k\ge 4} \prod_{\sum_{i=1}^k a_i = n} f(a_i) f(n)=k2i=1kai=nf(ai)+k4i=1kai=nf(ai)

#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n, md;
  cin >> n >> md;
  auto add = [&](int &x, int y) {
    x += y;
    if (x >= md) {
      x -= md;
    }
  };
  auto mul = [&](int x, int y) {
    return (long long) x * y % md;
  };
  vector<vector<int>> sum(4, vector<int>(n + 1));
  vector<int> dp(n + 1);
  dp[1] = sum[0][1] = 1;
  for (int i = 2; i <= n; ++i) {
    for (int j = 1; j < i; ++j) {
      for (int k = 3; k; --k) {
        add(sum[k][i], mul(dp[j], sum[k - 1][i - j]));
        if (k == 3) {
          add(sum[k][i], mul(dp[j], sum[k][i - j]));
        }
      }
    }
    dp[i] = sum[3][i];
    for (int k = 3; k; --k) {
      add(dp[i], sum[k][i]);
    }
    sum[0][i] = dp[i];
  }
  for (int i = 1; i <= n; ++i) {
    cout << dp[i] << "\n";
  }
  return 0;
}

Heretical … Möbius

注意到 4 , 9 , 25 , 49 4, 9, 25, 49 4,9,25,49 的倍数的 μ \mu μ 一定为 0 0 0 ,所以枚举余数爆搜即可。对于一个合法的序列要搜索的东西不多,加个卡时判无解即可。

#include 

using namespace std;

const int N = 200;
const int MAX = 1e9;
const int SQ = sqrt(MAX);

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  string pattern;
  for (int i = 0; i < 10; ++i) {
    string s;
    cin >> s;
    pattern += s;
  }
  int ans = MAX - N + 2;
  vector<bool> isprime(SQ + 1, true);
  vector<int> primes;
  for (int i = 2; i <= SQ; ++i) {
    if (isprime[i]) {
      primes.push_back(i);
      for (int j = i + i; j <= SQ; j += i) {
        isprime[j] = false;
      }
    }
  }
  bool ed = false;
  auto solve = [&](int l) {
    if (clock() > CLOCKS_PER_SEC * 0.9) {
      ed = true;
      return;
    }
    int r = l + N - 1;
    string s(N, '1');
    for (auto p : primes) {
      if (p * p > r) {
        break;
      }
      int q = p * p;
      for (int i = (l + q - 1) / q * q; i <= r; i += q) {
        s[i - l] = '0';
        if (pattern[i - l] == '1') {
          return;
        }
      }
    }
    if (s == pattern) {
      ans = l;
    }
  };
  for (int i = 1; i <= 44100; ++i) {
    bool ok = true;
    for (int j = 0; j < N; ++j) {
      if (((i + j) % 4 == 0 || (i + j) % 9 == 0 || (i + j) % 25 == 0 || (i + j) % 49 == 0) && pattern[j] == '1') {
        ok = false;
        break;
      }
    }
    if (ok) {
      for (int j = i; j < ans; j += 44100) {
        solve(j);
        if (ed) {
          break;
        }
      }
    }
    if (ed) {
      break;
    }
  }
  if (ans == MAX - N + 2) {
    ans = -1;
  }
  cout << ans << "\n";
  return 0;
}

Deja vu of … Go Players

n n n m m m 大小关系。

#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  cin >> tt;
  while (tt--) {
    int n, m;
    cin >> n >> m;
    cout << (n <= m ? "Yes" : "No") << "\n";
    for (int i = 0; i < n + m; ++i) {
      int x;
      cin >> x;
    }
  }
  return 0;
}

Immortal … Universe

大概是要DP前缀最小值之类的东西,倒着DP一遍即可。

#include 

using namespace std;

const int md = 998244353;

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline int mul(int x, int y) {
  return (long long) x * y % md;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  auto solve = [&](string s) {
    reverse(s.begin(), s.end());
    int n = s.size();
    vector<int> f(n * 2 + 1), g(n * 2 + 1);
    f[n] = 1;
    for (auto c : s) {
      vector<int> new_f(n * 2 + 1), new_g(n * 2 + 1);
      if (c != 'V') {
        for (int i = 0; i <= n * 2; ++i) {
          if (f[i]) {
            if (n <= i - 1) {
              add(new_g[n], f[i]);
            } else {
              add(new_f[i - 1], f[i]);
            }
          }
          if (g[i]) {
            add(new_g[min(n, i - 1)], g[i]);
          }
        }
      }
      if (c != 'P') {
        for (int i = 0; i <= n * 2; ++i) {
          if (f[i]) {
            add(new_f[i + 1], f[i]);
          }
          if (g[i]) {
            add(new_g[i + 1], g[i]);
          }
        }
      }
      swap(f, new_f);
      swap(g, new_g);
    }
    return make_pair(f, g);
  };
  string s, t;
  cin >> s >> t;
  pair<vector<int>, vector<int>> foo = solve(s);
  pair<vector<int>, vector<int>> bar = solve(t);
  int n = s.size(), m = t.size();
  int ans = 0;
  for (int i = 0; i <= n * 2; ++i) {
    for (int j = 0; j <= m * 2; ++j) {
      if (i + j > n + m) {
        add(ans, mul(foo.first[i] + foo.second[i], bar.first[j] + bar.second[j]));
      } else if (i + j == n + m) {
        add(ans, mul(foo.first[i], bar.first[j]));
      }
    }
  }
  cout << ans << "\n";
  return 0;
}

Interstellar … Fantasy

最短路一定在同一个平面上。

#include 

using namespace std;

class point {
 public:
  int x, y, z;

  point(int x = 0, int y = 0, int z = 0): x(x), y(y), z(z) {
  }

  point operator - (const point &b) const {
    return point(x - b.x, y - b.y, z - b.z);
  }

  int operator * (const point &b) const {
    return x * b.x + y * b.y + z * b.z;
  }

  int sqr() {
    return *this * *this;
  }

  double len() {
    return sqrt(sqr());
  }
};

long long sqr(int x) {
  return (long long) x * x;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  cout.setf(ios::fixed);
  cout.precision(10);
  int tt;
  cin >> tt;
  while (tt--) {
    point o, a, b;
    int r;
    cin >> o.x >> o.y >> o.z >> r;
    cin >> a.x >> a.y >> a.z;
    cin >> b.x >> b.y >> b.z;
    if ((a - b).sqr() == 0 || (o - a) * (b - a) <= 0 || (o - b) * (a - b) <= 0) {
      cout << (a - b).len() << "\n";
    } else {
      double h = sqrt((o - a).sqr() - (double) sqr((o - a) * (b - a)) / (a - b).sqr());
      if (r <= h) {
        cout << (a - b).len() << "\n";
      } else {
        double go_a = sqrt((o - a).sqr() - sqr(r));
        double go_b = sqrt((o - b).sqr() - sqr(r));
        double angle = atan2(sqrt((o - a).sqr() - h * h), h) + atan2(sqrt((o - b).sqr() - h * h), h) - atan2(go_a, r) - atan2(go_b, r);
        cout << angle * r + go_a + go_b << "\n";
      }
    }
  }
  return 0;
}

Omnipotent … Garland

特判掉 m = 1 m=1 m=1 的情况,无解当且仅当: n   m o d   k ≠ 0 n\bmod k\neq 0 nmodk̸=0 m k > n mk>n mk>n c n t B < 2 m cnt_{B}<2m cntB<2m

考虑构造 m = 2 m=2 m=2 的解,找到 4 4 4 B B B ,假设是 k 1 , k 2 , k 3 , k 4 k1, k2, k3, k4 k1,k2,k3,k4 ,构造 ( k 1 , k 2 , k 3 + 1 , k 3 + 2 , ⋯   , k 4 − 1 ) (k1, k2, k3+1, k3+2, \cdots, k4-1) (k1,k2,k3+1,k3+2,,k41) 和 $ (k1+1, k1+2, \cdots, k2-1, k3, k4)$ ,再将其他的按照   m o d   k \bmod k modk 的要求分配即可。如果找不到解,旋转一下就有解了。

#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  while (tt--) {
    int n, m, k;
    string str;
    cin >> n >> m >> k >> str;
    vector<int> a(n);
    int sum = 0;
    for (int i = 0; i < n; ++i) {
      a[i] = str[i] == 'B';
      sum += a[i];
    }
    if (n % k || (long long) m * k > n || sum < m * 2) {
      cout << "No" << "\n";
      continue;
    }
    if (m == 1) {
      bool ok = false;
      for (int i = 0; i < n; ++i) {
        if (a[i] && a[(i + 1) % n]) {
          ok = true;
          break;
        }
      }
      if (ok) {
        cout << "Yes" << "\n";
        cout << n;
        for (int i = 0; i < n; ++i) {
          cout << " " << i;
        }
        cout << "\n";
      } else {
        cout << "No" << "\n";
      }
      continue;
    }
    cout << "Yes" << "\n";
    for (int i = 0; i < n && sum > m * 2; ++i) {
      if (a[i]) {
        a[i] = 0;
        --sum;
      }
    }
    int k1 = -1, k2 = -1;
    for (int i = 0; i < n; ++i) {
      if (a[i]) {
        if (k1 == -1) {
          k1 = i;
        } else if (k2 == -1) {
          k2 = i;
        }
      }
    }
    vector<vector<int>> ans(m);
    if (k == 1) {
      int ptr = 0;
      for (int i = 0; i < n; ++i) {
        if (a[i]) {
          ans[ptr++ >> 1].push_back(i);
        } else {
          ans[i > k1 && i < k2].push_back(i);
        }
      }
      for (int i = 0; i < m; ++i) {
        cout << ans[i].size();
        for (auto x : ans[i]) {
          cout << " " << x;
        }
        cout << "\n";
      }
      continue;
    }
    vector<bool> visit(n);
    if (m & 1) {
      if (k2 - k1 + 1 >= k) {
        ans[m - 1].push_back(k1);
        visit[k1] = true;
        int cur = k - 2;
        for (int i = k1 + 1; i < k2 && cur; ++i) {
          if (!a[i]) {
            ans[m - 1].push_back(i);
            visit[i] = true;
            --cur;
          }
        }
        ans[m - 1].push_back(k2);
        visit[k2] = true;
      } else {
        int cur = k - 2;
        for (int i = 0; i < k1 && cur; ++i) {
          if (!a[i]) {
            ans[m - 1].push_back(i);
            visit[i] = true;
            --cur;
          }
        }
        ans[m - 1].push_back(k1);
        visit[k1] = true;
        ans[m - 1].push_back(k2);
        visit[k2] = true;
        for (int i = k2 + 1; i < n && cur; ++i) {
          if (!a[i]) {
            ans[m - 1].push_back(i);
            visit[i] = true;
            --cur;
          }
        }
      }
    }
    vector<vector<int>> candidates(m >> 1);
    int ptr0 = 0, ptr1 = 0, remain = max(k * 2 - 4, 2);
    for (int i = 0; i < n; ++i) {
      if (!visit[i]) {
        if (a[i]) {
          candidates[ptr1++ >> 2].push_back(i);
        } else {
          candidates[ptr0].push_back(i);
          if (!--remain) {
            if (ptr0 + 1 == m >> 1) {
              remain = n;
            } else {
              ++ptr0;
              remain = max(k * 2 - 4, 2);
            }
          }
        }
      }
    }
    auto add = [&](vector<int> p, int w) {
      int k1 = -1, k2 = -1, k3 = -1, k4 = -1;
      for (int i = 0; i < p.size(); ++i) {
        if (a[p[i]]) {
          if (k1 == -1) {
            k1 = i;
          } else if (k2 == -1) {
            k2 = i;
          } else if (k3 == -1) {
            k3 = i;
          } else if (k4 == -1) {
            k4 = i;
          }
        }
      }
      int need = (2 * k - 2 - (k4 - k3 - 1) % k) % k;
      for (int i = 0; i < p.size(); ++i) {
        if (i == k1 || i == k2) {
          ans[w].push_back(p[i]);
        } else if (i == k3 || i == k4) {
          ans[w + 1].push_back(p[i]);
        } else if (i > k1 && i < k2) {
          ans[w + 1].push_back(p[i]);
        } else if (i > k3 && i < k4) {
          ans[w].push_back(p[i]);
        } else if (need) {
          ans[w].push_back(p[i]);
          --need;
        } else {
          ans[w + 1].push_back(p[i]);
        }
      }
      if (need) {
        ans[w].clear();
        ans[w + 1].clear();
        need = (2 * k - 2 - (k3 - k2 - 1) % k) % k;
        for (int i = 0; i < p.size(); ++i) {
          if (i == k1 || i == k4) {
            ans[w].push_back(p[i]);
          } else if (i == k2 || i == k3) {
            ans[w + 1].push_back(p[i]);
          } else if (i < k1 || i > k4) {
            ans[w + 1].push_back(p[i]);
          } else if (i > k2 && i < k3) {
            ans[w].push_back(p[i]);
          } else if (need) {
            ans[w].push_back(p[i]);
            --need;
          } else {
            ans[w + 1].push_back(p[i]);
          }
        }
      }
    };
    for (int i = 0; i < m >> 1; ++i) {
      add(candidates[i], i * 2);
    }
    for (int i = 0; i < m; ++i) {
      cout << ans[i].size();
      for (auto x : ans[i]) {
        cout << " " << x;
      }
      cout << "\n";
    }
  }
  return 0;
}

Saintly … Coins

留坑,不打算填。

Misunderstood … Missing

倒着DP。

#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  cin >> tt;
  while (tt--) {
    int n;
    cin >> n;
    vector<int> a(n), b(n), c(n);
    for (int i = 0; i < n; ++i) {
      cin >> a[i] >> b[i] >> c[i];
    }
    int m = n * (n + 1) / 2 + 1;
    vector<vector<long long>> dp(n + 1, vector<long long>(m, -1));
    dp[0][0] = 0;
    for (int i = n - 1; ~i; --i) {
      vector<vector<long long>> new_dp(n + 1, vector<long long>(m, -1));
      for (int j = 0; j <= n; ++j) {
        for (int k = 0; k < m; ++k) {
          if (~dp[j][k]) {
            new_dp[j + 1][k + j + 1] = max(new_dp[j + 1][k + j + 1], dp[j][k] + a[i]);
            new_dp[j][k + j] = max(new_dp[j][k + j], dp[j][k] + (long long) b[i] * k);
            new_dp[j][k + j] = max(new_dp[j][k + j], dp[j][k] + (long long) c[i] * j);
          }
        }
      }
      swap(dp, new_dp);
    }
    long long ans = 0;
    for (int i = 0; i <= n; ++i) {
      ans = max(ans, *max_element(dp[i].begin(), dp[i].end()));
    }
    cout << ans << "\n";
  }
  return 0;
}

Philosophical … Balance

求出SA,按照height从大到小合并维护答案即可。

#include 

using namespace std;

template<typename T>
vector<int> suffix_array(const T &s, int n, int alpha) {
  vector<int> a(n);
  if (~alpha) {
    vector<int> bucket(alpha);
    for (int i = 0; i < n; ++i) {
      ++bucket[s[i]];
    }
    int sum = 0;
    for (int i = 0; i < alpha; ++i) {
      int add = bucket[i];
      bucket[i] = sum;
      sum += add;
    }
    for (int i = 0; i < n; ++i) {
      a[bucket[s[i]]++] = i;
    }
  } else {
    for (int i = 0; i < n; ++i) {
      a[i] = i;
    }
    sort(a.begin(), a.end(), [&](const int &x, const int &y) {
      return s[x] < s[y];
    });
  }
  vector<int> sorted_by_second(n);
  vector<int> ptr_group(n);
  vector<int> new_group(n);
  vector<int> group(n);
  group[a[0]] = 0;
  for (int i = 1; i < n; ++i) {
    group[a[i]] = group[a[i - 1]] + (s[a[i]] != s[a[i - 1]]);
  }
  int step = 1;
  while (group[a[n - 1]] < n - 1) {
    int ptr = 0;
    for (int i = n - step; i < n; ++i) {
      sorted_by_second[ptr++] = i;
    }
    for (int i = 0; i < n; ++i) {
      if (a[i] >= step) {
        sorted_by_second[ptr++] = a[i] - step;
      }
    }
    for (int i = n - 1; ~i; --i) {
      ptr_group[group[a[i]]] = i;
    }
    for (int i = 0; i < n; ++i) {
      int x = sorted_by_second[i];
      a[ptr_group[group[x]]++] = x;
    }
    new_group[a[0]] = 0;
    for (int i = 1; i < n; ++i) {
      if (group[a[i]] != group[a[i - 1]]) {
        new_group[a[i]] = new_group[a[i - 1]] + 1;
      } else {
        int prev = a[i - 1] + step >= n ? -1 : group[a[i - 1] + step];
        int now = a[i] + step >= n ? -1 : group[a[i] + step];
        new_group[a[i]] = new_group[a[i - 1]] + (prev != now);
      }
    }
    group = new_group;
    step <<= 1;
  }
  return a;
}

template<typename T>
vector<int> build_lcp(const T &s, int n, const vector<int> &sa) {
  vector<int> pos(n);
  for (int i = 0; i < n; ++i) {
    pos[sa[i]] = i;
  }
  vector<int> lcp(n - 1);
  for (int i = 0, k = 0; i < n; ++i) {
    k = max(k - 1, 0);
    if (pos[i] == n - 1) {
      k = 0;
    } else {
      int j = sa[pos[i] + 1];
      while (i + k < n && j + k < n && s[i + k] == s[j + k]) {
        ++k;
      }
      lcp[pos[i]] = k;
    }
  }
  return lcp;
}

class dsu {
 public:
  vector<int> p;
  int n;

  dsu(int n): n(n) {
    p.resize(n);
    for (int i = 0; i < n; ++i) {
      p[i] = i;
    }
  }

  inline int find(int x) {
    while (x != p[x]) {
      x = p[x] = p[p[x]];
    }
    return x;
  }

  inline bool unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) {
      return false;
    } else {
      p[x] = y;
      return true;
    }
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  cout.setf(ios::fixed);
  cout.precision(10);
  int tt;
  cin >> tt;
  while (tt--) {
    string s;
    cin >> s;
    int n = s.size();
    vector<int> sa = suffix_array(s, n, 256);
    vector<int> lcp = build_lcp(s, n, sa);
    dsu p(n);
    vector<double> ans(n);
    for (int i = 0; i < n; ++i) {
      ans[i] = n - sa[i];
    }
    vector<vector<int>> events(n);
    for (int i = 0; i < n - 1; ++i) {
      events[lcp[i]].push_back(i);
    }
    for (int i = n - 1; ~i; --i) {
      for (auto j : events[i]) {
        int k = p.find(j + 1);
        double prob = (ans[k] - i) / (ans[j] + ans[k] - i * 2);
        ans[k] = prob * ans[j] + (1 - prob) * i;
        p.unite(j, k);
      }
    }
    cout << ans[n - 1] << "\n";
  }
  return 0;
}

Desperate … Fire Survive

写个暴力就过了,可以证明复杂度正确。

#include 

using namespace std;

class node {
 public:
  int minv = 0;
  int maxv = 0;
  int cover = 0;
  long long sum = 0;
  
  inline void apply(int l, int r, int v) {
    minv = maxv = cover = v;
    sum = (long long) (r - l + 1) * v;
  }
};

class segtree {
 public:
  vector<node> tree;
  int n;

  inline node unite(const node &l, const node &r) {
    node res;
    res.minv = min(l.minv, r.minv);
    res.maxv = max(l.maxv, r.maxv);
    res.sum = l.sum + r.sum;
    return res;
  }

  segtree(int n): n(n) {
    tree.resize(n * 2 - 1);
  }

  inline void pull(int x, int z) {
    tree[x] = unite(tree[x + 1], tree[z]);
  }

  inline void push(int x, int l, int r) {
    int y = l + r >> 1, z = x + (y - l + 1 << 1);
    if (tree[x].cover) {
      tree[x + 1].apply(l, y, tree[x].cover);
      tree[z].apply(y + 1, r, tree[x].cover);
      tree[x].cover = 0;
    }
  }

  void build(int x, int l, int r) {
    if (l == r) {
      tree[x].apply(l, r, n);
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      build(x + 1, l, y);
      build(z, y + 1, r);
      pull(x, z);
    }
  }

  void reset(int x, int l, int r) {
    if (tree[x].minv == tree[x].maxv) {
      if (tree[x].minv != n) {
        tree[x].apply(l, r, query(tree[x].minv, tree[x].minv).minv);
      }
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      reset(x + 1, l, y);
      reset(z, y + 1, r);
      pull(x, z);
    }
  }

  int find_last(int x, int l, int r, int v) {
    if (tree[x].maxv <= v) {
      return r;
    } else if (tree[x].minv > v) {
      return -1;
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (tree[z].minv <= v) {
        return find_last(z, y + 1, r, v);
      } else {
        return find_last(x + 1, l, y, v);
      }
    }
  }

  template<typename... T>
  void modify(int x, int l, int r, int ll, int rr, const T&... v) {
    if (ll <= l && r <= rr) {
      tree[x].apply(l, r, v...);
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (ll <= y) {
        modify(x + 1, l, y, ll, rr, v...);
      }
      if (rr > y) {
        modify(z, y + 1, r, ll, rr, v...);
      }
      pull(x, z);
    }
  }

  node query(int x, int l, int r, int ll, int rr) {
    if (ll <= l && r <= rr) {
      return tree[x];
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (rr <= y) {
        return query(x + 1, l, y, ll, rr);
      } else if (ll > y) {
        return query(z, y + 1, r, ll, rr);
      } else {
        return unite(query(x + 1, l, y, ll, rr), query(z, y + 1, r, ll, rr));
      }
    }
  }

  void build() {
    build(0, 0, n - 1);
  }

  void reset() {
    reset(0, 0, n - 1);
  }

  int find_last(int v) {
    return find_last(0, 0, n - 1, v);
  }

  template<typename... T>
  void modify(int l, int r, const T&... v) {
    modify(0, 0, n - 1, l, r, v...);
  }

  node query(int l, int r) {
    return query(0, 0, n - 1, l, r);
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m, q;
  cin >> n >> m >> q;
  vector<int> a(n);
  vector<vector<int>> modifies(m);
  for (int i = 0; i < n; ++i) {
    cin >> a[i];
    --a[i];
    modifies[a[i]].push_back(i);
  }
  vector<int> l(q), r(q);
  vector<vector<int>> queries(m);
  for (int i = 0; i < q; ++i) {
    int w;
    cin >> l[i] >> r[i] >> w;
    --l[i];
    --r[i];
    --w;
    queries[w].push_back(i);
  }
  ++n;
  segtree seg(n);
  seg.build();
  vector<long long> ans(q);
  for (int i = 0; i < m; ++i) {
    seg.reset();
    for (auto j : modifies[i]) {
      int p = seg.find_last(j + 1);
      if (p + 1 <= j) {
        seg.modify(p + 1, j, j + 1);
      }
    }
    for (auto j : queries[i]) {
      int p = seg.find_last(r[j] + 1);
      if (p >= l[j]) {
        ans[j] = (long long) (p - l[j] + 1) * (r[j] + 2) - seg.query(l[j], p).sum;
      }
    }
  }
  for (int i = 0; i < q; ++i) {
    cout << ans[i] << "\n";
  }
  return 0;
}

Eventual … Journey

随便讨论一下。

#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m;
  cin >> n >> m;
  vector<int> a(n);
  vector<int> c(2);
  for (int i = 0; i < n; ++i) {
    cin >> a[i];
    ++c[a[i]];
  }
  vector<int> deg(n);
  for (int i = 0; i < m; ++i) {
    int from, to;
    cin >> from >> to;
    --from;
    --to;
    if (a[from] != a[to]) {
      ++deg[from];
      ++deg[to];
    }
  }
  vector<int> d(2);
  for (int i = 0; i < n; ++i) {
    if (deg[i]) {
      ++d[a[i]];
    }
  }
  for (int i = 0; i < n; ++i) {
    int ans = 0;
    if (!deg[i]) {
      ans += c[a[i]] - 1;
      ans += 2 * d[!a[i]];
      ans += 3 * (c[!a[i]] - d[!a[i]]);
    } else {
      ans += c[a[i]] - 1;
      ans += deg[i];
      ans += 2 * (c[!a[i]] - deg[i]);
    }
    if (i) {
      cout << " ";
    }
    cout << ans;
  }
  cout << "\n";
  return 0;
}

你可能感兴趣的:(CodeForces Gym 102056 简要题解)