P8528 [Ynoi2003] 铃原露露 题解
一道很好的启发式合并题目。
思路#
考虑一个事实。
我们想要求出对于每个点对不合法的情况。
例如现在考虑到了
有几种情况:
,那么是合法的。 ,那么包含 不包含 的区间是不合法的,即 。 ,那么包含 不包含 的区间是不合法的,即 。
我们考虑将询问离线,做一次扫描线。
考虑两种不合法的区间对于每个点来说都是连续的。
也就可以差分后做历史和。
同时考虑,对于一个相同的
那么只要对于每一个点在同一个
这一部分可以启发式合并来做,直接
而对于后面历史和部分。
我们使用线段树维护
Code#
代码很好写。
/**
* @file P8528.cpp
* @author mfeitveer
* @date 2023-11-25
*
* @copyright Copyright (c) 2023
*
*/
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
#define mp(x, y) make_pair(x, y)
#define eb(...) emplace_back(__VA_ARGS__)
#define fro(i, x, y) for(int i = (x);i <= (y);i++)
#define pre(i, x, y) for(int i = (x);i >= (y);i--)
#define dbg cerr << "Line " << __LINE__ << ": "
#define EVAL(x) #x " = " << (x)
typedef int64_t i64;
typedef uint32_t u32;
typedef uint64_t u64;
typedef __int128_t i128;
typedef __uint128_t u128;
typedef pair<int, int> PII;
bool ed;
const int N = 200010;
const int mod = 998244353;
int n, m, a[N], sz[N], sn[N], fa[N], tn[N], dep[N];
vector<int> to[N]; set<int> son[N];
vector<tuple<int, int, int>> fin, w[N];
i64 ans[N]; vector<PII> que[N];
i64 t1[N<<1], t2[N<<1], t3[N<<1], tg1[N<<1], tg2[N<<1];
inline void push1(int p, int v)
{ tg1[p] += v, t3[p] += v; }
inline void push2(int p, int v)
{ tg2[p] += v, t1[p] += t2[p] * v; }
inline void pdo(int p, int mid)
{
if(tg1[p]) push1(mid<<1, tg1[p]), push1(mid<<1|1, tg1[p]);
if(tg2[p])
{
if(t3[mid<<1] <= t3[mid<<1|1]) push2(mid<<1, tg2[p]);
if(t3[mid<<1] >= t3[mid<<1|1]) push2(mid<<1|1, tg2[p]);
}
tg1[p] = tg2[p] = 0;
}
inline void pup(int p, int mid)
{
t1[p] = t1[mid<<1] + t1[mid<<1|1], t2[p] = 0;
t2[p] += (t3[mid<<1] <= t3[mid<<1|1]) * t2[mid<<1];
t2[p] += (t3[mid<<1] >= t3[mid<<1|1]) * t2[mid<<1|1];
t3[p] = min(t3[mid<<1], t3[mid<<1|1]);
}
inline void build(int p, int l, int r)
{
if(l == r) return t2[p] = 1, void();
int mid = (l + r) >> 1;
build(mid<<1, l, mid);
build(mid<<1|1, mid + 1, r);
pup(p, mid);
}
inline void upd1(int p, int l, int r, int ls, int rs, int k)
{
if(ls <= l && r <= rs) return push1(p, k);
int mid = (l + r) / 2; pdo(p, mid);
if(mid >= ls) upd1(mid<<1, l, mid, ls, rs, k);
if(mid < rs) upd1(mid<<1|1, mid + 1, r, ls, rs, k);
pup(p, mid);
}
inline void upd2(int p, int l, int r, int ls, int rs, int k)
{
if(t3[p] > 0) return;
if(ls <= l && r <= rs) return push2(p, k);
int mid = (l + r) / 2; pdo(p, mid);
if(mid >= ls) upd2(mid<<1, l, mid, ls, rs, k);
if(mid < rs) upd2(mid<<1|1, mid + 1, r, ls, rs, k);
pup(p, mid);
}
inline i64 ask(int p, int l, int r, int ls, int rs)
{
if(ls <= l && r <= rs) return t1[p];
int mid = (l + r) / 2; i64 sum{}; pdo(p, mid);
if(mid >= ls) sum += ask(mid<<1, l, mid, ls, rs);
if(mid < rs) sum += ask(mid<<1|1, mid + 1, r, ls, rs);
return sum;
}
inline void merge(int x, int y)
{
if(son[x].size() < son[y].size())
swap(son[x], son[y]);
for(auto i : son[y])
{
auto it = son[x].lower_bound(i);
if(it != son[x].end())
fin.eb(*it, i, a[x]);
if(it != son[x].begin())
fin.eb(*prev(it), i, a[x]);
}
for(auto i : son[y]) son[x].insert(i); son[y].clear();
}
inline void dfs(int x)
{
son[x].insert(a[x]);
for(auto i : to[x])
{
if(i == fa[x]) continue;
dfs(i), merge(x, i);
}
}
inline void solve()
{
cin >> n >> m;
fro(i, 1, n) cin >> a[i];
fro(i, 2, n) cin >> fa[i];
fro(i, 2, n) to[fa[i]].eb(i);
dfs(1), build(1, 1, n);
for(auto [x, y, z] : fin)
{
if(x > y) swap(x, y);
if(x <= z && z <= y) continue;
if(y < z)
w[y].eb(1, x, 1),
w[z].eb(1, x, -1);
if(z < x)
w[y].eb(z + 1, x, 1);
}
fro(i, 1, m)
{
int l, r;
cin >> l >> r;
que[r].eb(l, i);
}
fro(i, 1, n)
{
for(auto [x, y, z] : w[i])
upd1(1, 1, n, x, y, z);
upd2(1, 1, n, 1, i, 1);
for(auto [l, id] : que[i])
ans[id] = ask(1, 1, n, l, i);
}
fro(i, 1, m) cout << ans[i] << "\n";
}
bool st;
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
double Mib = fabs((&ed-&st)/1048576.), Lim = 1024;
cerr << " Memory: " << Mib << "\n", assert(Mib<=Lim);
solve();
return 0;
}
作者:JiaY19
出处:https://www.cnblogs.com/JiaY19/p/17855335.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)