10.21

没时间写题了,写点题解。一道题写了一晚上,效率有点低。。。

多校A层冲刺NOIP2024模拟赛09 区间

给定一个长度为 \(N\) 的数列 \(A_1,A_2,\dots,A_N\) 和一个长度为 \(N−1\) 的数列 \(B_2,B_3,\dots,B_N\)

\(Q\) 个询问,每次询问是一个区间 \([L_i,R_i]\)。请你求出有多少二元组 \((l,r)\) 满足:

  • \(L_i \leq l < r \leq R_i\)

  • \(\forall i\in\{l+1,l+2,\dots,r-1\}, A_l>A_i\)(如果 \(l+1=r\) 则忽略这一条件,认为符合)

  • \(\forall i\in\{l,l+1,\dots,r-1\}, B_r>A_i\)

把询问离线下来,扫描线,把询问挂在右端点。

对于第一次个限制可以用单调栈维护​,栈内元素严格递减。

对于 \(B_i\) 在单调栈中二分看有哪些 \(A_i\) 符合条件,对于这些元素记录一次版本。

用历史和线段树可以轻松做。

#include <bits/stdc++.h>

using namespace std;

using ubt = long long;

int read() {
  int x;
  cin >> x;
  return x;
}

const int maxN = 3e5 + 7;

int n, m, a[maxN], b[maxN];

vector<pair<int, int>> q[maxN];

int top, stk[maxN];

int tg[maxN * 4];
struct dat {
  ubt v, h;
  friend dat operator + (dat A, dat B) {
    dat res;
    res.v = A.v + B.v;
    res.h = A.h + B.h;
    return res;
  }
} t[maxN * 4];
#define ls (p << 1)
#define rs (p << 1 | 1)
void make(int p, int v) {
  tg[p] += v;
  t[p].h += t[p].v * v;
}
void down(int p) {
  if (!tg[p]) return;
  make(ls, tg[p]);
  make(rs, tg[p]);
  tg[p] = 0;
}
void change(int K, int v, int l, int r, int p) {
  if (l == r) {
    t[p].v += v;
    return;
  }
  down(p);
  int mid = (l + r) >> 1;
  K <= mid ? change(K, v, l, mid, ls) : change(K, v, mid + 1, r, rs);
  t[p] = t[ls] + t[rs];
}
void add(int L, int R, int l, int r, int p) {
  if (L <= l && r <= R) {
    make(p, 1);
    return;
  }
  down(p);
  int mid = (l + r) >> 1;
  if (L <= mid)
    add(L, R, l, mid, ls);
  if (R > mid)
    add(L, R, mid + 1, r, rs);
  t[p] = t[ls] + t[rs];
}

ubt ask(int L, int R, int l, int r, int p) {
  if (L <= l && r <= R)
    return t[p].h;
  down(p);
  int mid = (l + r) >> 1;
  ubt res = 0;
  if (L <= mid)
    res = ask(L, R, l, mid, ls);
  if (R > mid)
    res += ask(L, R, mid + 1, r, rs);
  return res;
}

ubt ans[maxN];

int main() {
  freopen("interval.in", "r", stdin);
  ofstream cout("interval.out");

  n = read();
  for (int i = 1; i <= n; i++) a[i] = read();
  for (int i = 2; i <= n; i++) b[i] = read();
  m = read();
  for (int i = 1; i <= m; i++) {
    int l = read(), r = read();
    q[r].emplace_back(l, i);
  }

  stk[top = 1] = 1;
  change(1, 1, 1, n, 1);
  for (int i = 2; i <= n; i++) {
    auto erfen = [](int l, int r, int x) {
      int pos = 1e9;
      while (l <= r) {
        int mid = (l + r) >> 1;
        if (a[stk[mid]] >= x)
          l = mid + 1;
        else
          r = mid - 1, pos = mid;
      }
      return pos;
    };

    int pos = erfen(1, top, b[i]);

    if (pos != 1e9)
      add(stk[pos], i, 1, n, 1);

    for (auto [l, id] : q[i])
      ans[id] = ask(l, i, 1, n, 1);

    while (top && a[stk[top]] <= a[i])
      change(stk[top], -1, 1, n, 1), top--;
    stk[++top] = i;
    change(i, 1, 1, n, 1);
  }

  for (int i = 1; i <= m; i++)
    cout << ans[i] << '\n';
}

多校A层冲刺NOIP2024模拟赛10
不让走最短路中最后一条边的最短路

我没脑子,只会暴力数据结构。

考场上直接秒了,但有细节问题,但数据水直接过了,但后来加强了,但 90 多分,但还是没过,但排名没掉。

最短路唯一,那可以建出最短路树。

对于每个节点的答案就是不能经过与父亲的连边。

那每个点的答案就是子树内的点与子树外的点的连边贡献的。

考虑数据结构暴力维护。

没写完。明天补。

upd.

把每个连接子树外的边塞到平衡树里,记录连接的点的 dfs 序作为二叉搜索树性质的键值(因为当合并子树的信息时会有两个节点都在当前子树的边,需要删去),记录一个权值表示到根节点的最短距离。

合并子树信息时暴力 merge 就好了,注意多了一条边,所以要区间(全局)加。
删除子树内的边非常方便,起点不用考虑,所有终点在这颗子树内的删掉就好了。

非常暴力。
https://www.cnblogs.com/ccxswl/p/18493701

#include <bits/stdc++.h>

using namespace std;

int read() {
  int s = 0, w = 1;
  char c = getchar();
  while (!isdigit(c)) {
    w = c == '-' ? -w : w;
    c = getchar();
  }
  while (isdigit(c)) {
    s = s * 10 + c - 48;
    c = getchar();
  }
  return s * w;
}

const int inf = 1e9;
const int maxN = 1e5 + 7;

int n, m;

int head[maxN], tot;
struct edge {
  int to, ls, w;
} e[maxN * 4];
void add(int u, int v, int w) {
  e[++tot] = {v, head[u], w};
  head[u] = tot;
}

int dis[maxN], pre[maxN], prw[maxN];
bool vis[maxN];
using pii = pair<int, int>;
void dij() {
  fill(dis + 1, dis + n + 1, inf);
  dis[1] = 0;
  priority_queue<pii, vector<pii>, greater<pii>> Q;
  Q.emplace(0, 1);
  while (!Q.empty()) {
    int f = Q.top().second;
    Q.pop();
    if (vis[f]) continue;
    vis[f] = true;
    for (int i = head[f]; i; i = e[i].ls) {
      int to = e[i].to, w = e[i].w;
      if (dis[to] > dis[f] + w) {
        pre[to] = f, prw[to] = w;
        dis[to] = dis[f] + w;
        Q.emplace(dis[to], to);
      }
    }
  }
}

struct wei {
  int to, w;
  wei(int to, int w) : to(to), w(w) {}
  friend bool operator < (wei A, wei B) {
    return A.to < B.to;
  }
};
vector<wei> E[maxN];

int dfn[maxN], cnt, siz[maxN];
void initdfs(int x) {
  dfn[x] = ++cnt;
  siz[x] = 1;
  for (auto [to, w] : E[x])
    initdfs(to), siz[x] += siz[to];
}

mt19937 rd(5222568);
int nwn, root[maxN];
struct tree {
  int l, r;
  int to, w;
  int key;
  int siz;
  int mn;
  int tg;
} t[maxN * 4];
int New(int to, int v) {
  int p = ++nwn;
  t[p].l = t[p].r = t[p].tg = 0;
  t[p].siz = 1;
  t[p].to = to;
  t[p].mn = t[p].w = v;
  t[p].key = rd();
  return p;
}
void upd(int p) {
  t[p].siz = t[t[p].l].siz + t[t[p].r].siz + 1;
  t[p].mn = min({t[t[p].l].mn, t[t[p].r].mn, t[p].w});
}
void make(int p, int v) {
  if (!p) return;
  t[p].mn += v;
  t[p].w += v;
  t[p].tg += v;
}
void down(int p) {
  if (!t[p].tg) return;
  make(t[p].l, t[p].tg);
  make(t[p].r, t[p].tg);
  t[p].tg = 0;
}
int merge(int x, int y) {
  if (!x || !y) return x | y;
  if (t[x].key <= t[y].key) {
    down(x);
    t[x].r = merge(t[x].r, y);
    upd(x);
    return x;
  } else {
    down(y);
    t[y].l = merge(x, t[y].l);
    upd(y);
    return y;
  }
}
void split(int p, int k, int &x, int &y) {
  if (!p) x = y = 0;
  else {
    down(p);
    if (t[p].to <= k)
      x = p, split(t[p].r, k, t[x].r, y);
    else
      y = p, split(t[p].l, k, x, t[y].l);
    upd(p);
  }
}
int M(int x, int y) {
  if (!x || !y) return x | y;
  if (t[x].key > t[y].key) swap(x, y);
  int L, R;
  down(x), down(y);
  split(y, t[x].to, L, R);
  t[x].l = M(t[x].l, L);
  t[x].r = M(t[x].r, R);
  upd(x);
  return x;
}
void insert(int &p, int to, int v) {
  int L, R;
  split(p, to, L, R);
  p = merge(merge(L, New(to, v)), R);
}
void del(int &p, int x) {
  int L, M, R;
  split(p, dfn[x] + siz[x] - 1, L, R);
  split(L, dfn[x] - 1, L, M); // 考场这里忘减 1 了。
  p = merge(L, R);
}

int ans[maxN];
void dfs(int x) {
  for (auto [to, w] : E[x]) {
    dfs(to);
    make(root[to], w);
    root[x] = M(root[x], root[to]);
  }
  for (int i = head[x]; i; i = e[i].ls) {
    int to = e[i].to, w = e[i].w;

    if (dfn[x] <= dfn[to] && dfn[to] <= dfn[x] + siz[x] - 1)
      continue;
    if (to == pre[x] && w == prw[x]) continue;

    insert(root[x], dfn[to], w + dis[to]);
  }
  del(root[x], x);

  ans[x] = root[x] ? t[root[x]].mn : -1;
}

signed main() {
//  freopen("in.in", "r", stdin);
//  ofstream cout("out.out");

  t[0].mn = inf;

  n = read(), m = read();
  for (int i = 1; i <= m; i++) {
    int u = read(), v = read(), w = read();
    add(u, v, w), add(v, u, w);
  }
  dij();

  for (int i = 1; i <= n; i++)
    if (pre[i])
      E[pre[i]].emplace_back(i, prw[i]);

  initdfs(1);

  dfs(1);

  for (int i = 2; i <= n; i++)
    cout << ans[i] << '\n';
}
posted @ 2024-10-21 21:40  ccxswl  阅读(22)  评论(0编辑  收藏  举报