\(\text{Solution}\)

简要的口胡

线段树维护合法左端点数量

正序枚举 \(i\),将其视为右端点,去除不合法的左端点,统计贡献

再将其视为中间点,由它产生的左端点在线段树上区间加

注意到一个重复出现的 \(b\) 值,上一个相同位置的贡献不能再要

于是把这个点废掉

考场上又打了棵线段树,统计答案的线段树只需去掉被废掉的点即可

直接跑了 \(949ms\),两只 \(\text{log}\) 踩线过(后时限开到 \(2s\),不算踩线了,可仍然垫底)

\(\text{Code}\)

#include <cstdio>
#include <algorithm>
#define ls (p << 1)
#define rs (ls | 1)
#define re register
#define LL long long
using namespace std; const int N = 2e5 + 5;
int n, b[N], l1[N], l2[N];
LL ans; int sum[N << 2], tag[N << 2], del[N << 2]; inline void remove(int p, int l, int r, int x)
{
if (x < l || x > r) return;
if (l == r) return void(del[p] = 1);
int mid = (l + r) >> 1;
if (x <= mid) remove(ls, l, mid, x);
else remove(rs, mid + 1, r, x);
del[p] = del[ls] + del[rs];
}
inline int count(int p, int l, int r, int x, int y)
{
if (x > y || y < l || x > r) return 0;
if (x <= l && r <= y) return del[p];
int mid = (l + r) >> 1, res = 0;
if (x <= mid) res = count(ls, l, mid, x, y);
if (y > mid) res += count(rs, mid + 1, r, x, y);
return res;
} inline void pushdown(int p, int l, int r)
{
if (!tag[p]) return;
int mid = (l + r) >> 1;
sum[ls] += (mid - l + 1 - count(1, 1, n, l, mid)) * tag[p], tag[ls] += tag[p];
sum[rs] += (r - mid - count(1, 1, n, mid + 1, r)) * tag[p], tag[rs] += tag[p];
tag[p] = 0;
}
void update(int p, int l, int r, int x, int y, int v)
{
if (x > y || y < l || x > r) return;
if (x <= l && r <= y)
{
sum[p] += v * (r - l + 1 - count(1, 1, n, l, r)), tag[p] += v;
return;
}
pushdown(p, l, r);
int mid = (l + r) >> 1;
if (x <= mid) update(ls, l, mid, x, y, v);
if (y > mid) update(rs, mid + 1, r, x, y, v);
sum[p] = sum[ls] + sum[rs];
}
int query(int p, int l, int r, int x, int y)
{
if (x > y || y < l || x > r) return 0;
if (x <= l && r <= y) return sum[p];
pushdown(p, l, r);
int mid = (l + r) >> 1, res = 0;
if (x <= mid) res = query(ls, l, mid, x, y);
if (y > mid) res += query(rs, mid + 1, r, x, y);
return res;
} int main()
{
scanf("%d", &n);
for(re int i = 1; i <= n; i++) scanf("%d", &b[i]);
for(re int i = 1; i <= n; i++)
{
update(1, 1, n, l2[b[i]] + 1, l1[b[i]] - 1, -1);
update(1, 1, n, l1[b[i]], l1[b[i]], -query(1, 1, n, l1[b[i]], l1[b[i]]));
remove(1, 1, n, l1[b[i]]), ans += query(1, 1, n, l1[b[i]] + 1, i - 2);
update(1, 1, n, l1[b[i]] + 1, i - 1, 1), l2[b[i]] = l1[b[i]], l1[b[i]] = i;
}
printf("%lld\n", ans);
}

其实只需将第二个线段树改为树状数组,尽管还是两只 \(\text{log}\),但快了很多

\(\text{Code}\)

#include <cstdio>
#include <algorithm>
#define ls (p << 1)
#define rs (ls | 1)
#define re register
#define LL long long
using namespace std; const int N = 2e5 + 5;
int n, b[N], l1[N], l2[N], c[N];
LL ans; int sum[N << 2], tag[N << 2], del[N << 2]; inline int lowbit(int x){return x & (-x);}
inline void remove(int x, int v)
{
if (!x) return;
for(; x <= n; x += lowbit(x)) c[x] += v;
}
inline int querysum(int x)
{
if (!x) return 0;
int res = 0;
for(; x; x -= lowbit(x)) res += c[x];
return res;
}
inline int count(int x, int y){return querysum(y) - querysum(x - 1);} inline void pushdown(int p, int l, int r)
{
if (!tag[p]) return;
int mid = (l + r) >> 1;
sum[ls] += (mid - l + 1 - count(l, mid)) * tag[p], tag[ls] += tag[p];
sum[rs] += (r - mid - count(mid + 1, r)) * tag[p], tag[rs] += tag[p];
tag[p] = 0;
}
void update(int p, int l, int r, int x, int y, int v)
{
if (x > y || y < l || x > r) return;
if (x <= l && r <= y)
{
sum[p] += v * (r - l + 1 - count(l, r)), tag[p] += v;
return;
}
pushdown(p, l, r);
int mid = (l + r) >> 1;
if (x <= mid) update(ls, l, mid, x, y, v);
if (y > mid) update(rs, mid + 1, r, x, y, v);
sum[p] = sum[ls] + sum[rs];
}
int query(int p, int l, int r, int x, int y)
{
if (x > y || y < l || x > r) return 0;
if (x <= l && r <= y) return sum[p];
pushdown(p, l, r);
int mid = (l + r) >> 1, res = 0;
if (x <= mid) res = query(ls, l, mid, x, y);
if (y > mid) res += query(rs, mid + 1, r, x, y);
return res;
} int main()
{
scanf("%d", &n);
for(re int i = 1; i <= n; i++) scanf("%d", &b[i]);
for(re int i = 1; i <= n; i++)
{
update(1, 1, n, l2[b[i]] + 1, l1[b[i]] - 1, -1);
update(1, 1, n, l1[b[i]], l1[b[i]], -query(1, 1, n, l1[b[i]], l1[b[i]]));
remove(l1[b[i]], 1), ans += query(1, 1, n, l1[b[i]] + 1, i - 2);
update(1, 1, n, l1[b[i]] + 1, i - 1, 1), l2[b[i]] = l1[b[i]], l1[b[i]] = i;
}
printf("%lld\n", ans);
}

其实要在线段树上废掉一个点,只要将这个线段树带上系数,把这一位系数改成 \(0\) 即可

\(Code\)

#include <cstdio>
#include <algorithm>
#define ls (p << 1)
#define rs (ls | 1)
#define re register
#define LL long long
using namespace std; const int N = 2e5 + 5;
int n, b[N], l1[N], l2[N];
LL ans; int sum[N << 2], tag[N << 2], c[N << 2];
inline void pushdown(int p, int l, int r)
{
if (!tag[p]) return;
int mid = (l + r) >> 1;
sum[ls] += c[ls] * tag[p], tag[ls] += tag[p];
sum[rs] += c[rs] * tag[p], tag[rs] += tag[p];
tag[p] = 0;
}
inline void change(int p, int l, int r, int x, int v)
{
if (x < l || x > r) return;
if (l == r)
{
c[p] = v, sum[p] = v * tag[p];
return;
}
pushdown(p, l, r);
int mid = (l + r) >> 1;
if (x <= mid) change(ls, l, mid, x, v);
else change(rs, mid + 1, r, x, v);
sum[p] = sum[ls] + sum[rs], c[p] = c[ls] + c[rs];
}
void update(int p, int l, int r, int x, int y, int v)
{
if (x > y || y < l || x > r) return;
if (x <= l && r <= y)
{
sum[p] += v * c[p], tag[p] += v;
return;
}
pushdown(p, l, r);
int mid = (l + r) >> 1;
if (x <= mid) update(ls, l, mid, x, y, v);
if (y > mid) update(rs, mid + 1, r, x, y, v);
sum[p] = sum[ls] + sum[rs], c[p] = c[ls] + c[rs];
}
int query(int p, int l, int r, int x, int y)
{
if (x > y || y < l || x > r) return 0;
if (x <= l && r <= y) return sum[p];
pushdown(p, l, r);
int mid = (l + r) >> 1, res = 0;
if (x <= mid) res = query(ls, l, mid, x, y);
if (y > mid) res += query(rs, mid + 1, r, x, y);
return res;
} int main()
{
scanf("%d", &n);
for(re int i = 1; i <= n; i++) scanf("%d", &b[i]);
for(re int i = 1; i <= n; i++)
{
update(1, 1, n, l2[b[i]] + 1, l1[b[i]] - 1, -1), change(1, 1, n, l1[b[i]], 0);
ans += query(1, 1, n, l1[b[i]] + 1, i - 2);
update(1, 1, n, l1[b[i]] + 1, i - 1, 1), change(1, 1, n, i, 1);
l2[b[i]] = l1[b[i]], l1[b[i]] = i;
}
printf("%lld\n", ans);
}

【USACO 2021 US Open, Platinum】United Cows of Farmer John的更多相关文章

  1. 孤独的照片【USACO 2021 December Contest Bronze】

    孤独的照片 Farmer John 最近购入了 \(N\) 头新的奶牛,每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一. 奶牛目前排成一排,Farmer John 想要为 ...

  2. 洛谷 P2812 校园网络【[USACO]Network of Schools加强版】 解题报告

    P2812 校园网络[[USACO]Network of Schools加强版] 题目背景 浙江省的几所OI强校的神犇发明了一种人工智能,可以AC任何题目,所以他们决定建立一个网络来共享这个软件.但是 ...

  3. P2812 校园网络【[USACO]Network of Schools加强版】

    题目背景 浙江省的几所OI强校的神犇发明了一种人工智能,可以AC任何题目,所以他们决定建立一个网络来共享这个软件.但是由于他们脑力劳动过多导致全身无力身体被♂掏♂空,他们来找你帮助他们. 题目描述 共 ...

  4. luogu P2812 校园网络【[USACO]Network of Schools加强版】|Tarjan

    题目背景 浙江省的几所OI强校的神犇发明了一种人工智能,可以AC任何题目,所以他们决定建立一个网络来共享这个软件.但是由于他们脑力劳动过多导致全身无力身体被♂掏♂空,他们来找你帮助他们. 题目描述 共 ...

  5. 【USACO 2.1.1】城堡

    [题目描述] 我们憨厚的USACO主人公农夫约翰(Farmer John)以无法想象的运气,在他生日那天收到了一份特别的礼物:一张“幸运爱尔兰”(一种彩票).结果这张彩票让他获得了这次比赛唯一的奖品— ...

  6. 【USACO】草地排水

    Drainage Ditches 草地排水 usaco 4.2.1描述在农夫约翰的农场上,每逢下雨,Bessie最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一 ...

  7. POJ 1986 Distance Queries / UESTC 256 Distance Queries / CJOJ 1129 【USACO】距离咨询(最近公共祖先)

    POJ 1986 Distance Queries / UESTC 256 Distance Queries / CJOJ 1129 [USACO]距离咨询(最近公共祖先) Description F ...

  8. 题解 【USACO 4.2.1】草地排水

    [USACO 4.2.1]草地排水 Description 在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫 ...

  9. 1642: 【USACO】Payback(还债)

    1642: [USACO]Payback(还债) 时间限制: 1 Sec 内存限制: 64 MB 提交: 190 解决: 95 [提交] [状态] [讨论版] [命题人:外部导入] 题目描述 &quo ...

  10. 1519: 【USACO】超级书架

    1519: [USACO]超级书架 时间限制: 1 Sec 内存限制: 64 MB 提交: 1735 解决: 891 [提交] [状态] [讨论版] [命题人:外部导入] 题目描述 Farmer Jo ...

随机推荐

  1. 【实习项目介绍】XXXXX大数据平台介绍

    一.技术架构 1.整体介绍及架构 (1)概述 Odeon大数据平台以全图形化Web操作的形式为用户提供一站式的大数据能力:包括数据采集.任务编排.调度及处理.数据展现(BI)等:同时提供完善的权限管理 ...

  2. nuxt.js框架 如何打包 build

    nuxt脚手架开发好项目后怎么打包 以下是脚手架的package.json部分代码 "scripts": { "dev": "cross-env NO ...

  3. Linux基础守护进程、高级IO、进程间通信

    守护进程(Daemon) 前言 Linux常用于服务器,程序通常不运行在前台.运行于前台的进程和终端关联,一旦终端关闭,进程也随之退出.因为守护进程不和终端关联,因此它的标准输出和标准输入也无法工作, ...

  4. 分享一个项目中在用的图片处理工具类(图片缩放,旋转,画布格式,字节,image,bitmap转换等)

    using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Dra ...

  5. [OpenCV实战]12 使用深度学习和OpenCV进行手部关键点检测

    目录 1 背景 2 实现 3 结果和代码 4 参考 手部关键点检测是在手指上找到关节以及在给定图像中找到指尖的过程.它类似于在脸部(面部关键点检测)或身体(人体姿势估计)上找到关键点.但是手部检测不同 ...

  6. [论文总结] kmeans聚类和WGCNA

    kmeans聚类和WGCNA 文章目录 kmeans聚类和WGCNA 论文1 论文2 论文3 总结 总结了3篇论文中kmeans聚类和WGCNA的运用. 论文1 Comprehensive disse ...

  7. Hadoop详解(05) – MapReduce

    Hadoop详解(05) – MapReduce MapReduce概述 定义 MapReduce是一个分布式运算程序的编程框架,是用户 "基于Hadoop的数据分析应用" 开发的 ...

  8. 算法学习笔记(3): 倍增与ST算法

    倍增 目录 倍增 查找 洛谷P2249 重点 变式练习 快速幂 ST表 扩展 - 运算 扩展 - 区间 变式答案 倍增,字面意思即"成倍增长" 他与二分十分类似,都是基于" ...

  9. 解决xcode每次编译都需要输入用户名和密码

    MacOS:11.1 Xcode:12.3 一.打开你的 钥匙串, 如果不知道  打开你的 spotlight搜索 工具 ,输入"钥匙串" 二.登录--->iPhone de ...

  10. 01-逻辑仿真工具VCS使用

    1 逻辑仿真工具VCS的使用 在书写完成RTL代码之后,确保自己书写的代码和自己想要的逻辑是一致的. VCS是synopsys公司下的的仿真工具. 1 VCS仿真过程 编译-->仿真--> ...