P9990 [Ynoi Easy Round 2023] TEST_90 题解
很容易想到离线扫描线。
考虑离线从
考虑扫描过程的转移。从前往后扫描时显然可以动态维护
于是我们要维护支持区间反转,历史版本和的线段树。每个节点额外开个
具体看代码注释:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int N = 1e6 + 5;
int n, m, a[N];
long long ans[N];
vector<pair<int, int>> v[N];
class SegmentTree
{
public:
struct Node
{
int l, r;
long long sum;
long long hsum;
bool tag;
long long tg[2];
}tr[N << 2];
void pushup(int u)
{
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
tr[u].hsum = tr[u << 1].hsum + tr[u << 1 | 1].hsum;
}
void pushdown(int u)
{
tr[u << 1].hsum += tr[u << 1].sum * tr[u].tg[0] + tr[u].tg[1] * (tr[u << 1].r - tr[u << 1].l + 1 - tr[u << 1].sum); // 有 tr[u].tg[0] 个没有反转和 tr[u].tg[1] 个有反转
if (tr[u].tag)
{
tr[u << 1].sum = (tr[u << 1].r - tr[u << 1].l + 1) - tr[u << 1].sum; // 正常维护 tag
}
tr[u << 1].tg[0] += tr[u].tg[tr[u << 1].tag], tr[u << 1].tg[1] += tr[u].tg[tr[u << 1].tag ^ 1];
// 如果左儿子处于反转状态,即 tag = 1,那么 tg[0] 应该加上 u 点的 tg[1],tg[1] 同理
tr[u << 1].tag ^= tr[u].tag;
// 右儿子同理
tr[u << 1 | 1].hsum += tr[u << 1 | 1].sum * tr[u].tg[0] + tr[u].tg[1] * (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1 - tr[u << 1 | 1].sum);
if (tr[u].tag)
{
tr[u << 1 | 1].sum = (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) - tr[u << 1 | 1].sum;
}
tr[u << 1 | 1].tg[0] += tr[u].tg[tr[u << 1 | 1].tag], tr[u << 1 | 1].tg[1] += tr[u].tg[tr[u << 1 | 1].tag ^ 1];
tr[u << 1 | 1].tag ^= tr[u].tag;
tr[u].tag = 0;
tr[u].tg[0] = tr[u].tg[1] = 0;
}
void build(int u, int l, int r)
{
tr[u] = { l, r, 0LL, 0LL, 0, {0LL, 0LL} };
if (l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
}
void update(int u, int l, int r)
{
if (tr[u].l >= l and tr[u].r <= r)
{
tr[u].tag ^= 1;
tr[u].tg[tr[u].tag]++;
tr[u].sum = (tr[u].r - tr[u].l + 1) - tr[u].sum;
tr[u].hsum += tr[u].sum;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) update(u << 1, l, r);
else
{
// 如果另一边不需要反转,也需要记录 hsum 和 tg
tr[u << 1].tg[tr[u << 1].tag]++;
tr[u << 1].hsum += tr[u << 1].sum;
}
if (r > mid) update(u << 1 | 1, l, r);
else
{
// 如果另一边不需要反转,也需要记录 hsum 和 tg
tr[u << 1 | 1].tg[tr[u << 1 | 1].tag]++;
tr[u << 1 | 1].hsum += tr[u << 1 | 1].sum;
}
pushup(u);
}
long long query(int u, int l, int r)
{
if (tr[u].l >= l and tr[u].r <= r)
{
return tr[u].hsum;
}
pushdown(u);
long long res = 0LL;
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) res = query(u << 1, l, r);
if (r > mid) res = res + query(u << 1 | 1, l, r);
return res;
}
}sgt;
int lstpos[N];
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
cin >> m;
for (int i = 1; i <= m; i++)
{
int l, r;
cin >> l >> r;
v[r].emplace_back(make_pair(i, l));
}
sgt.build(1, 1, n);
for (int i = 1; i <= n; i++)
{
int p = lstpos[a[i]];
lstpos[a[i]] = i;
sgt.update(1, p + 1, i);
for (auto& [id, l] : v[i])
{
ans[id] += sgt.query(1, l, i);
}
}
for (int i = 1; i <= m; i++) cout << ans[i] << "\n";
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现