CF1801E Gasoline prices 题解
考虑方案数如何计算。注意到树上一些点有着相同的取值,于是如果我们将它们用并查集缩起来,它的可行取值范围就是
然后我们考虑怎么实现。启发式合并直接用 std::set
就可以暴力做。对于一条路径我们可以拆成两条链,分类讨论维护一下信息即可。这个树上数据结构第一想法是线段树结合树链剖分,但这样一来内层的复杂度是
#include <bits/stdc++.h>
#define N 200005
#define M 18
#define ull unsigned long long
#define ll long long
#define mod 1000000007
using namespace std;
ll qpow(ll x) {
ll y = mod - 2, ans = 1;
while (y) {
if (y & 1) ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans;
}
int n;
struct node {
int to, nxt;
} t[N];
int head[N], cnt;
void add(int u, int v) {
t[++cnt].to = v;
t[cnt].nxt = head[u];
head[u] = cnt;
}
int dfn[N], rk[N], tot;
int dep[N], siz[N], anc[M][N], top[N], son[N], f[N];
int tpt;
void dfs1(int x, int fa) {
f[x] = anc[0][x] = fa;
dep[x] = dep[fa] + 1;
siz[x] = 1;
for (int i = head[x]; i; i = t[i].nxt) {
int y = t[i].to;
dfs1(y, x);
siz[x] += siz[y];
if (siz[son[x]] < siz[y]) son[x] = y;
}
}
void dfs2(int x, int tp) {
dfn[x] = ++tot;
rk[tot] = x;
top[x] = tp;
if (!son[x]) return;
dfs2(son[x], tp);
for (int i = head[x]; i; i = t[i].nxt)
if (t[i].to != son[x])
dfs2(t[i].to, t[i].to);
}
int LCA(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
x = f[top[x]];
}
return dep[x] > dep[y] ? y : x;
}
const ull bas = 131;
ull fac[N], inv[N];
int tqt;
struct BIT {
int lbt(int x) {
return x & (-x);
}
ull tree[N];
void ad(int x, ull vl) {
++tqt;
while (x <= n) tree[x] += vl, x += lbt(x);
}
void add(int x, int y, ull vl) {
ad(x, vl);
ad(y + 1, -vl);
}
ull ask(int x) {
++tqt;
ull ans = 0;
while (x) ans += tree[x], x -= lbt(x);
return ans;
}
} U, D;
ll ans = 1;
int ml[N], mr[N];
struct DSU {
int fa[N];
int fnd(int x) {
return x == fa[x] ? x : fa[x] = fnd(fa[x]);
}
set<int>st[N];
int l[N], r[N];
void mge(int x, int y) {
x = fnd(x), y = fnd(y);
if (x == y) return;
if (st[x].size() < st[y].size()) swap(x, y);
fa[y] = x;
ans = ans * qpow(r[x] - l[x] + 1) % mod;
ans = ans * qpow(r[y] - l[y] + 1) % mod;
l[x] = max(l[x], l[y]), r[x] = min(r[x], r[y]);
ans = ans * max(r[x] - l[x] + 1, 0) % mod;
for (auto i : st[y]) {
st[x].insert(i);
U.add(dfn[i], dfn[i] + siz[i] - 1, (x - y) * fac[dep[i]]);
D.add(dfn[i], dfn[i] + siz[i] - 1, (x - y) * inv[dep[i]]);
}
st[y].clear();
}
void init() {
for (int i = 1; i <= n; i++) {
fa[i] = i;
l[i] = ml[i], r[i] = mr[i];
ans = ans * (mr[i] - ml[i] + 1) % mod;
U.add(dfn[i], dfn[i] + siz[i] - 1, i * fac[dep[i]]);
D.add(dfn[i], dfn[i] + siz[i] - 1, i * inv[dep[i]]);
st[i].insert(i);
}
}
} dsu;
ull gt(int x, int y) {
return (U.ask(dfn[x]) - U.ask(dfn[f[y]])) * inv[dep[y]];
}
ull tg(int x, int y) {
return (D.ask(dfn[y]) - D.ask(dfn[f[x]])) * fac[dep[y]];
}
vector<int>v[N];
int gtk(int x, int k) {
++tpt;
for (int i = M - 1; i >= 0; i--)
if ((k >> i) & 1) x = anc[i][x];
return x;
}
ull fnd(int x, int y, int k, int l) {
if (dep[l] + k <= dep[x]) {
int p = gtk(x, k);
return gt(x, p);
}
ull ans = gt(x, l);
k -= dep[x] - dep[l];
int p = gtk(y, dep[y] - dep[l] - k);
return ans * fac[k] + tg(gtk(y, dep[y] - dep[l] - 1), p);
}
int fd(int x, int y, int k, int l) {
if (dep[l] + k <= dep[x]) return gtk(x, k);
k -= dep[x] - dep[l];
int p = gtk(y, dep[y] - dep[l] - k);
return p;
}
ull qw(ull x, ull y) {
ull ans = 1;
while (y) {
if (y & 1) ans *= x;
x *= x;
y >>= 1;
}
return ans;
}
int main() {
fac[0] = inv[0] = 1;
for (int i = 1; i < N; i++) fac[i] = fac[i - 1] * bas;
ull ivb = qw(fac[1], ULONG_LONG_MAX);
for (int i = 1; i < N; i++) inv[i] = inv[i - 1] * ivb;
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
for (int i = 2; i <= n; i++) {
int x;
cin >> x;
add(x, i);
}
for (int i = 1; i <= n; i++) cin >> ml[i] >> mr[i];
for (int i = 0; i <= n; i++) {
for (int j = M - 1; j >= 0; j--)
if ((i >> j) & 1)
v[i].push_back(j);
}
dfs1(1, 0);
dfs2(1, 1);
for (int j = 1; j < M; j++)
for (int i = 1; i <= n; i++)
anc[j][i] = anc[j - 1][anc[j - 1][i]];
dsu.init();
int q;
cin >> q;
while (q--) {
int a, b, c, d;
cin >> a >> b >> c >> d;
if (ans == 0) {
cout << "0\n";
continue;
}
int la = LCA(a, b), lc = LCA(c, d), lh = dep[a] + dep[b] - 2 * dep[la];
while (fnd(a, b, lh, la) != fnd(c, d, lh, lc)) {
int l = 0, r = lh, mid = 0, as = 0;
while (l <= r) {
mid = (l + r) >> 1;
if (fnd(a, b, mid, la) != fnd(c, d, mid, lc)) as = mid, r = mid - 1;
else l = mid + 1;
}
int na = fd(a, b, as, la), nc = fd(c, d, as, lc);
dsu.mge(na, nc);
}
cout << ans << "\n";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现