10.21
没时间写题了,写点题解。一道题写了一晚上,效率有点低。。。
给定一个长度为 \(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';
}