2025.3.2 の 总结

A

一个很重要的性质:

\(\gcd(a_1, a_2, \dots, a_n) = \gcd(b_1, b_2, \dots, b_n)\) 其中 \(b\)\(a\) 的差分数组,也就是 \(b_i = a_i - a_{i - 1}\)

这个时候就可以使用线段树维护 \(b\) 数组,区间加就能转化为差分数组的单点修改,而查询最大公约数也能直接在线段树上查询,然后就变成板子力。

B

把柿子抠出来就是 \(\gcd(a_{h1, w1}, a_{h1, w1 + 1}, \dots, a_{h1 + 1, w1}, a_{h1 + 1, w1 + 1}, \dots, a_{h2, w2})\),然后使用 A 的那个小技巧,就能拆成 \(\gcd(a_{h1, w1}, a_{h1, w1 + 1} - a_{h1, w1}, \dots, a_{h1 + 1, w1}, a_{h1 + 1, w1 + 1} - a_{h1 + 1, w1}, \dots)\),根据 \(a\) 数组的定义就能变成 \(\gcd(a_{h1, w1}, B_{w1 + 1} - B_{w1}, \dots, a_{h1 + 1, w1}, B_{w1 + 1} - B_{w1}, \dots)\) 然后发现有一坨相同的史,去重变成 \(\gcd(a_{h1, w1}, a_{h1 + 1, w1}, \dots, a_{h2, w1}, B_{w1 + 1} - B_{w1}, \dots)\),然后根据 \(a\) 的定义,再去重,其实就是把,又能变成 \(\gcd(a_{h1, w1}, A_{h1 + 1} - A_{h1}, \dots, B_{w1 + 1} - B_{w1}, \dots)\),然后 \(A, B\) 这两坨直接 ST 表做,\(a_{h1, w1} = A_{h1} + B_{w1}\),然后就没了。

C

可以直接两个树状数组做:一个代表如果还没修好时这一天的最大产量,一个代表修好时这一天的最大产量,然后单点修改分两段区间查询就好了。

D

这题的关键就是 \(lst_i\),代表上一个 \(a_i\) 出现的位置,把询问按 \(r\) 排序让它右端点不减,线段树上的每个节点 \(x\) 的值 \(t_x\) 代表后面一个这个数 \(a_x\) 出现的位置,然后双指针一下就能线性搞出来,然后每个询问的答案就是 \(\min_{i = L_i} ^ {i \leq R_i} t_i\),线段树上查询就做完了。

E

套路,以前考试的时候见过。

看到没有修改,拿计算器弄一下发现 \(\max(a_i) = 10^{12}\) 只需要开个六七次根就成一了,而对一开根是没有意义的,所以线段树记录的就是这段区间的和以及最大值,当这段要开根的区间最大值等于一时继续开根时无意义的,直接返回,查询就是普通查询。

F

发现能活下来的蚂蚁一定是这段区间 \([l_i, r_i]\)\(\gcd(a_{l_i}, a_{l_i + 1}, \dots, a_{r_i})\),然后线段树要维护的就变成了这段区间的最大公约数和有多少个数等于最大公约数,然后在线从线段树上抠答案。

G

反方向的思考发现,最大合法括号序列的长度就是区间总长减去不合法的括号总长,而后者一定长成 \(\dots)))(((\dots\) 这个样,然后线段树维护区间内未匹配的左右括号数量,答案就是区间总和减一下这段区间没匹配的括号数量。

代码们

// A
#include <iostream>

using namespace std;
using ll = long long;

const int N = 5e5 + 5;

struct Node {
  ll x, g;
} s[N << 2];

ll n, m, t[N], a[N];

ll gcd( ll a, ll b ) {
  return !b ? a : gcd(b, a % b);
}

void push_up( int x ) {
  s[x].x = s[x << 1].x + s[x << 1 | 1].x;
  s[x].g = gcd(s[x << 1].g, s[x << 1 | 1].g);
}

void update( int i, int l, int r, int p, ll v ) {
  if (l > i || r < i) {
    return ;
  }
  if (l == r) {
    s[p].x += v, s[p].g += v;
    return ;
  }
  int mid = l + r >> 1;
  update(i, l, mid, p << 1, v);
  update(i, mid + 1, r, p << 1 | 1, v);
  push_up(p);
}

ll query( int l, int r, int nl, int nr, int p ) {
  if (nl > r || nr < l || r > n || nl > nr) {
    return 0;
  }
  if (nl >= l && nr <= r) {
    return s[p].g;
  }
  ll mid = nl + nr >> 1, g = query(l, r, nl, mid, p << 1);
  g = gcd(abs(g), abs(query(l, r, mid + 1, nr, p << 1 | 1)));
  return g;
}

void add( int x, ll k ) {
  for (; x <= n; x += (x & -x)) {
    t[x] += k;
  }
}

ll ask( int x ) {
  ll res = 0;
  for (; x; x -= (x & -x)) {
    res += t[x];
  }
  return res;
}

int main() {
  ios :: sync_with_stdio(0), cin.tie(0);
  cin >> n >> m;
  for (int i = 1; i <= n; ++i) {
    cin >> a[i];
    add(i, a[i]), add(i + 1, -a[i]);
  }
  for (int i = 1; i <= n; ++i) {
    update(i, 1, n, 1, a[i] - a[i - 1]);
  }
  for (ll l, r, d; m--; ) {
    char op; cin >> op;
    if (op == 'C') {
      cin >> l >> r >> d;
      update(l, 1, n, 1, d);
      update(r + 1, 1, n, 1, -d);
      add(l, d), add(r + 1, -d);
    } else {
      cin >> l >> r;
      if (l ^ r) {
        cout << gcd(abs(ask(l)), abs(query(l + 1, r, 1, n, 1))) << endl;
      } else {
        cout << abs(ask(l)) << endl;
      }
    }
  }
  return 0;
}
// B
#include <iostream>

using namespace std;

const int N = 2e5 + 5, Log = 20;

int n, m, a[N], b[N], lg[N], f[2][Log][N];

int gcd( int a, int b ) {
  return !b ? a : gcd(b, a % b);
}

int query0( int l, int r ) {
  int lg2 = lg[r - l + 1];
  return gcd(f[0][lg2][l], f[0][lg2][r - (1 << lg2) + 1]);
}

int query1( int l, int r ) {
  int lg2 = lg[r - l + 1];
  return gcd(f[1][lg2][l], f[1][lg2][r - (1 << lg2) + 1]);
}

int main() {
  ios :: sync_with_stdio(0), cin.tie(0);
  cin >> n >> m;
  for (int i = 1; i <= n; cin >> a[i++]) {
  }
  for (int i = 1; i <= n; cin >> b[i++]) {
  }
  for (int i = 2; i <= n; ++i) {
    lg[i] = lg[i >> 1] + 1;
  }
  for (int i = 1; i <= n; ++i) {
    f[0][0][i] = abs(a[i] - a[i - 1]);
    f[1][0][i] = abs(b[i] - b[i - 1]);
  }
  for (int i = 1; i < Log; ++i) {
    for (int j = 1; j <= n - (1 << i) + 1; ++j) {
      f[0][i][j] = gcd(f[0][i - 1][j], f[0][i - 1][j + (1 << i - 1)]);
      f[1][i][j] = gcd(f[1][i - 1][j], f[1][i - 1][j + (1 << i - 1)]);
    }
  }
  for (int x, y, xx, yy; m--; ) {
    cin >> x >> xx >> y >> yy;
    int ans = a[x] + b[y];
    if (x ^ xx) {
      ans = gcd(ans, query0(x + 1, xx));
    }
    if (y ^ yy) {
      ans = gcd(ans, query1(y + 1, yy));
    }
    cout << ans << endl;
  }
  return 0;
}
// C
#include <iostream>

#define int long long

using namespace std;

const int N = 2e5 + 5;

int n, k, a, b, Q, t1[N], t2[N];

void update1( int x, int k ) {
  for (; x <= n; x += (x & -x)) {
    t1[x] += k;
  }
}

void update2( int x, int k ) {
  for (; x <= n; x += (x & -x)) {
    t2[x] += k;
  }
}

int query1( int x ) {
  int res = 0;
  for (; x; x -= (x & -x)) {
    res += t1[x];
  }
  return res;
}

int query2( int x ) {
  int res = 0;
  for (; x; x -= (x & -x)) {
    res += t2[x];
  }
  return res;
}

signed main() {
  ios :: sync_with_stdio(0), cin.tie(0);
  cin >> n >> k >> b >> a >> Q;
  for (int op, d, q, p; Q--; ) {
    cin >> op;
    if (op == 1) {
      cin >> d >> q;
      update1(d, min(a - query1(d) + query1(d - 1), q));
      update2(d, min(b - query2(d) + query2(d - 1), q));
    } else {
      cin >> p;
      cout << query1(p - 1) + query2(n) - query2(p + k - 1) << endl;
    }
  }
  return 0;
}
// D
#include <iostream>
#include <cmath>

#define int long long

using namespace std;

const int N = 1e5 + 5;

struct Node {
  int x, Max;
} t[N << 2];

int n, m, a[N];

void push_up( int x ) {
  t[x].x = t[x << 1].x + t[x << 1 | 1].x;
  t[x].Max = max(t[x << 1].Max, t[x << 1 | 1].Max);
}

void update( int l, int r, int nl, int nr, int p ) {
  if (nl > r || nr < l || t[p].Max == 1) {
    return ;
  }
  if (nl == nr) {
    t[p].x = t[p].Max = sqrt(t[p].x);
    return ;
  }
  int mid = nl + nr >> 1;
  update(l, r, nl, mid, p << 1);
  update(l, r, mid + 1, nr, p << 1 | 1);
  push_up(p);
}

int query( int l, int r, int nl, int nr, int p ) {
  if (nl > r || nr < l) {
    return 0;
  }
  if (nl >= l && nr <= r) {
    return t[p].x;
  }
  int mid = nl + nr >> 1;
  int res = query(l, r, nl, mid, p << 1);
  res += query(l, r, mid + 1, nr, p << 1 | 1);
  return res;
}

void build( int l, int r, int p ) {
  if (l == r) {
    t[p].x = t[p].Max = a[l];
    return ;
  }
  int mid = l + r >> 1;
  build(l, mid, p << 1);
  build(mid + 1, r, p << 1 | 1);
  push_up(p);
}

signed main() {
  ios :: sync_with_stdio(0), cin.tie(0);
  cin >> n;
  for (int i = 1; i <= n; cin >> a[i++]) {
  }
  build(1, n, 1);
  cin >> m;
  for (int op, l, r; m--; ) {
    cin >> op >> l >> r;
    if (l > r) {
      swap(l, r);
    }
    if (op == 0) {
      update(l, r, 1, n, 1);
    } else {
      cout << query(l, r, 1, n, 1) << '\n';
    }
  }
  return 0;
}
// E
#include <iostream>
#include <cmath>

#define int long long

using namespace std;

const int N = 1e5 + 5;

struct Node {
  int s, g;
} t[N << 2];

int n, m, T, a[N];

int gcd( int a, int b ) {
  return !b ? a : gcd(b, a % b);
}

void push_up( int x ) {
  if (gcd(t[x << 1].g, t[x << 1 | 1].g) == t[x << 1].g) {
    t[x].s += t[x << 1].s;
  }
  if (gcd(t[x << 1].g, t[x << 1 | 1].g) == t[x << 1 | 1].g) {
    t[x].s += t[x << 1 | 1].s;
  }
  t[x].g = gcd(t[x << 1].g, t[x << 1 | 1].g);
}

Node query( int l, int r, int nl, int nr, int p ) {
  if (nl > r || nr < l) {
    return {0, 0};
  }
  if (nl >= l && nr <= r) {
    return t[p];
  }
  int mid = nl + nr >> 1;
  Node res = query(l, r, nl, mid, p << 1), tmp = query(l, r, mid + 1, nr, p << 1 | 1), ret = {0, 0};
  if (gcd(res.g, tmp.g) == res.g) {
    ret.s += res.s;
  }
  if (gcd(res.g, tmp.g) == tmp.g) {
    ret.s += tmp.s;
  }
  ret.g = gcd(res.g, tmp.g);
  return ret;
}

void build( int l, int r, int p ) {
  if (l == r) {
    t[p].g = a[l], t[p].s = 1;
    return ;
  }
  int mid = l + r >> 1;
  build(l, mid, p << 1);
  build(mid + 1, r, p << 1 | 1);
  push_up(p);
}

signed main() {
  ios :: sync_with_stdio(0), cin.tie(0);
  cin >> n;
  for (int i = 1; i <= n; cin >> a[i++]) {
  }
  build(1, n, 1);
  cin >> T;
  for (int i = 1, l, r; i <= T; ++i) {
    cin >> l >> r;
    cout << (r - l + 1) - query(l, r, 1, n, 1).s << endl;
  }
  return 0;
}
// G
#include <iostream>
#include <cmath>

#define int long long

using namespace std;

const int N = 1e6 + 5;

struct Node {
  int l, r;
} t[N << 2];

int n, T, l, r;
string s;

void push_up( int x ) {
  t[x].l = t[x << 1 | 1].l + t[x << 1].l - min(t[x << 1].l, t[x << 1 | 1].r);
  t[x].r = t[x << 1].r + t[x << 1 | 1].r - min(t[x << 1].l, t[x << 1 | 1].r);
}

Node query( int l, int r, int nl, int nr, int p ) {
  if (nl > r || nr < l) {
    return {0, 0};
  }
  if (nl >= l && nr <= r) {
    return {t[p].l, t[p].r};
  }
  int mid = nl + nr >> 1;
  Node res = query(l, r, nl, mid, p << 1), res1 = query(l, r, mid + 1, nr, p << 1 | 1);
  Node ret = {res1.l + res.l - min(res.l, res1.r), res.r + res1.r - min(res.l, res1.r)};
  return ret;
}

void build( int l, int r, int p ) {
  if (l == r) {
    if (s[l] == '(') {
      t[p].l = 1;
    } else {
      t[p].r = 1;
    }
    return ;
  }
  int mid = l + r >> 1;
  build(l, mid, p << 1);
  build(mid + 1, r, p << 1 | 1);
  push_up(p);
}

signed main() {
  ios :: sync_with_stdio(0), cin.tie(0);
  cin >> s >> T, n = s.size(), s = " " + s, build(1, n, 1);
  for (; T--; ) {
    cin >> l >> r;
    cout << (r - l + 1) - query(l, r, 1, n, 1).l - query(l, r, 1, n, 1).r << endl;
  }
  return 0;
}
posted @ 2025-03-02 20:54  Ja_Morant  阅读(29)  评论(0)    收藏  举报