XJTUPC2023
J. 大秦酒店欢迎您
题解
我们考虑莫队
首先我们预处理出处于位置\(x\)的颜色下一次出现的位置\(nxt[x]\)以及上一次出现的位置\(pre[x]\)
莫队上维护一下信息:
\(Ans\):\([l,r]\)的所有子区间的颜色数之和
\(num\):\([l,r]\)的颜色数
\(Lans\):\([l,l],[l,l + 1],[l,l + 2]...[l,r]\)这些区间的颜色数之和
\(Rans\):\([r,r],[r - 1, r],[r - 2, r]...[l,r]\)这些区间的颜色数之和
\(cnt[x]\):颜色\(x\)的出现次数
- 我们以左端点\(l\)向左扩张为例, 表示左端点向左扩张对维护的信息的影响
\(l:=l-1\)
\(cnt[col[l]]:=cnt[col[l]] + 1\),颜色出现次数更新的同时更新\(num\)
\(Rans:=Rans + num\)
\(Lans := Lans + min(r, nxt[l]-1) - l + 1\)
\(Ans := Ans + Lans\)
- 那么对于其他操作的影响也是类似的
const int mod = (1ll << 32);
const int N = 5e5 + 10, M = 4e5 + 10;
const int B = sqrt(N) + 1;
int n, q, a[N];
int id[N], Ans, Lans, Rans, num, cnt[N], nxt[N], pre[N], ans[N], pos[N];
struct QUERY
{
int l, r, idx;
bool operator<(const QUERY &t) const
{
if (id[l] == id[t.l])
{
if (id[l] & 1)
return r < t.r;
else
return r > t.r;
}
else
return l < t.l;
}
} qry[N];
void del(int l, int r, int op)
{
if (op == 1) // Left
{
Ans -= Lans;
Lans -= min(r, nxt[l] - 1) - l + 1;
Rans -= num;
cnt[a[l]]--;
if (cnt[a[l]] == 0)
num--;
}
else // Right
{
Ans -= Rans;
Rans -= r - max(l, pre[r] + 1) + 1;
Lans -= num;
cnt[a[r]]--;
if (cnt[a[r]] == 0)
num--;
}
}
void add(int l, int r, int op)
{
if (op == 1) // Left
{
cnt[a[l]]++;
if (cnt[a[l]] == 1)
num++;
Rans += num;
Lans += min(r, nxt[l] - 1) - l + 1;
Ans += Lans;
}
else // Right
{
cnt[a[r]]++;
if (cnt[a[r]] == 1)
num++;
Lans += num;
Rans += r - max(l, pre[r] + 1) + 1;
Ans += Rans;
}
}
void solve()
{
cin >> n >> q;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
pre[i] = 0;
if (pos[a[i]])
{
pre[i] = pos[a[i]];
nxt[pos[a[i]]] = i;
}
pos[a[i]] = i;
nxt[i] = n + 1;
}
for (int i = 1; i <= q; ++i)
{
cin >> qry[i].l >> qry[i].r;
qry[i].idx = i;
}
for (int i = 1; i <= n; ++i) // 分块
id[i] = (i - 1) / B + 1;
sort(qry + 1, qry + q + 1); // 对查询进行排序
for (int i = 1, l = 1, r = 0; i <= q; ++i)
{
while (l > qry[i].l)
add(--l, r, 1);
while (r < qry[i].r)
add(l, ++r, 2);
while (l < qry[i].l)
del(l++, r, 1);
while (r > qry[i].r)
del(l, r--, 2);
ans[qry[i].idx] = Ans;
}
for (int i = 1; i <= q; ++i)
cout << ans[i] % mod << endl;
}
M. 斑马子树
\(1 \leq n \leq 10^5\)
题解
- 我们考虑如果一颗子树是斑马子树,那么这颗子树能够产生贡献的时间区间段是多少
- 我们考虑\(dp\)出子树\(u\)中最早变成斑马子树的时间戳\(l\),最晚变成非斑马子树的时间戳\(r\)
- 那么\([l,r]\)的时间段上\(u\)的贡献一直为\(1\),我们考虑差分,最后前缀和统计答案即可
// M. 斑马子树
const int N = 2e5 + 10, M = 4e5 + 10;
int n, t[N], mi[N], mx[N], ans[N];
vector<int> g[N];
void dfs(int u, int par)
{
mi[u] = mx[u] = t[u];
for (auto v : g[u])
{
if (v == par)
continue;
dfs(v, u);
mi[u] = min(mi[u], mi[v]);
mx[u] = max(mx[u], mx[v]);
}
ans[mi[u]]++;
ans[mx[u]]--;
}
void solve()
{
cin >> n;
for (int i = 2; i <= n; ++i)
{
int u;
cin >> u;
g[u].push_back(i);
g[i].push_back(u);
}
for (int i = 1; i <= n; ++i)
{
int u;
cin >> u;
t[u] = i;
}
dfs(1, 0);
for (int i = 1; i <= n; ++i)
{
ans[i] = ans[i - 1] + ans[i];
cout << ans[i] << "\n "[i < n];
}
}
随机推荐
- 鸿蒙应用开发:如何与组件库(Glide)衔接?
Android 发展到现在不仅提供了很多 API,还提供了很多第三方库.这降低了我们开发者的开发难度,提升了开发效率,让应用开发更加的简单高效.众所周知,HarmonyOS 除了提供 16000 ...
- 小tips: HTTP 请求过程示例图及名称解释
一个 HTTP 请求过程示例图: 一个 HTTP 请求需要经历以上过程,接下来看一个具体的例子: 名词解释: Queueing: 在请求队列中的时间. Stalled: 从TCP 连接建立完成,到真正 ...
- C++17新特性探索:拥抱std::optional,让代码更优雅、更安全
std::optional 背景 在编程时,我们经常会遇到可能会返回/传递/使用一个确定类型对象的场景.也就是说,这个对象可能有一个确定类型的值也可能没有任何值.因此,我们需要一种方法来模拟类似指针的 ...
- Angular Material 18+ 高级教程 – CDK Layout の Breakpoints
前言 CDK Layout 主要是用于处理 Breakpoints,它底层是依靠 window.matchMedia 来实现的. Material Design 2 & 3 Breakpoin ...
- CSS – Font Family
前言 font-family 虽然只是一个 CSS 属性, 但是牵连许多东西, 所以独立一篇来讲. 网站一般上会使用 Google Fonts 作为 font-family, 下面会以一个 Googl ...
- 微信小程序开发疑难
1.开发者工具在小程序webview中注入wx时会提示token过期,但真机正常
- SpringBoot——项目快速启动
SpringBoot项目快速启动 对SpringBoot项目打包(执行Maven构建指令package) 执行后会生成对应的项目 jar包,在文件夹找到该文件 在对应文件夹下即可执行 j ...
- [The Trellor] Chapter 1
翻译软件真的翻不好,读英文小说要相信你的脑子. There's only one thing to do in Berlen - that is listening the sound of wind ...
- template<> 模板特化
template<> 是用于 模板特化(Template Specialization) 的一种语法. 模板特化允许你为某些特定的模板参数提供不同的实现.例如,template<&g ...
- 流式dma和一致性dma的区别
流式 DMA(Streaming DMA)和一致性 DMA(Consistent DMA)是两种不同的内存映射模式,用于 DMA(直接内存访问)操作.它们的主要区别在于缓存一致性.性能和使用场景.以下 ...


