\(Orz\) 各位题解大佬,我来膜拜一发

还有单调栈实在没弄懂

法一:线段树+堆

首先,讨论区间的个数的题目,我们可以想到枚举一个端点\(r\),找到所有的\(l\)

我们不妨设:\(ml[i]\)为第i种颜色出现的最小位置,\(mr[i]\)为第i种出现的最大位置

我们想到对于一个右端点,他有那些值是不能选的:

假设有一种颜色的\(mr\)值比当前枚举的右端点小,则\([ml, mr]\)里面的所有的左端点都不能选,对应到线段树中就是区间赋成0

再假设有一种颜色,当前枚举的右端点在\([ml[i], mr[i]]\)之间,那么我们记录一个\(last[i]\),表示小于当前右端点的最大的i

那么\([1, last[i]]\)所有的值都不能选

然后我们要找到一个最大的last,用一个堆即可

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define int long long
il int read() {
re int x = 0, f = 1; re char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
return x * f;
}
#define rep(i, s, t) for(re int i = s; i <= t; ++ i)
#define mem(k, p) memset(k, p, sizeof(k))
#define ls k * 2
#define rs k * 2 + 1
#define maxn 300005
int n, m, a[maxn], last[maxn], ans, ml[maxn], mr[maxn], tag[maxn << 2], sum[maxn << 2];
struct node {int id, val; il bool operator < (const node&x) const{return val < x.val;}};
priority_queue<node> q;
il void pushdown(int k, int l, int r, int mid) {
if(tag[k] == -1) return;
sum[ls] = (mid - l + 1) * tag[k], sum[rs] = (r - mid) * tag[k];
tag[ls] = tag[rs] = tag[k]; tag[k] = -1;
}
il void modify(int k, int l, int r, int ll, int rr, int x) {
if(l > rr || ll > r) return;
if(ll <= l && r <= rr) return (void)(tag[k] = x, sum[k] = (r - l + 1) * x);
int mid = (l + r) >> 1; pushdown(k, l, r, mid);
modify(ls, l, mid, ll, rr, x), modify(rs, mid + 1, r, ll, rr, x);
sum[k] = sum[ls] + sum[rs];
}
il int query(int k, int l, int r, int ll, int rr) {
if(l > rr || ll > r) return 0;
if(ll <= l && r <= rr) return sum[k];
int mid = (l + r) >> 1; pushdown(k, l, r, mid);
return query(ls, l, mid, ll, rr) + query(rs, mid + 1, r, ll, rr);
}
il void solve() {
n = read(), ans = 0, mem(tag, -1), modify(1, 1, n, 1, n, 1);
while(!q.empty()) q.pop();
rep(i, 1, n) ml[i] = n + 1, mr[i] = last[i] = 0;
rep(i, 1, n) a[i] = read(), ml[a[i]] = min(ml[a[i]], i), mr[a[i]] = max(mr[a[i]], i);
rep(i, 1, n) {
last[a[i]] = i, q.push((node){a[i], last[a[i]]});
if(i == mr[a[i]]) modify(1, 1, n, ml[a[i]] + 1, mr[a[i]], 0);
while(!q.empty()) {
int x = q.top().id;
if(last[x] == mr[x]) q.pop();
else break;
}
int pax = (q.empty() ? 1 : q.top().val + 1);
ans += query(1, 1, n, pax, i);
}
printf("%lld\n", ans);
}
signed main() {
int T = read();
while(T --) solve();
return 0;
}

随机化

对于每一个位置,我们需要随机一个值,然后需要保证相同的颜色的所有的随机值异或结果为\(0\)

由于异或满足$a\ \(^\)\ b = 0$,所以我们把每个颜色的除了最后一项的所有随机值异或起来,让最后一位等于这个随机值

然后我们不难发现,每一个满足条件的一段区间,他的异或的值显然是等于0的

所以问题就转化成了:有多少区间的异或和等于0

由于上述异或的性质,于是我们只需要用\(map\)存一下即可

跟据@\(Ebola\)大佬的证明,我们的错误率是很小的。

\(Code:\)

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define debug printf("Now is Line : %d\n",__LINE__)
#define file(a) freopen(#a".in","r",stdin);freopen(#a".out","w",stdout)
#define int long long
il int read() {
re int x = 0, f = 1; re char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
return x * f;
}
#define rep(i, s, t) for(re int i = s; i <= t; ++ i)
#define drep(i, s, t) for(re int i = t; i >= s; -- i)
#define Next(i, u) for(re int i = head[u]; i; i = e[i].next)
#define mem(k, p) memset(k, p, sizeof(k))
#define lb(x) (x)&(-(x))
#define ls k * 2
#define rs k * 2 + 1
#define maxn 300005
int n, m, a[maxn], val[maxn];
vector<int>q[maxn];
map<int, int> p;
il int Random() {
return 1ll * rand() * rand() * rand();
}
signed main() {
srand(time(0));
int T = read();
while(T --) {
n = read();
rep(i, 1, n) a[i] = read(), q[a[i]].push_back(i), val[i] = 0;
rep(i, 1, n) {
int sum = 0;
for(re int j = 0; j < q[i].size(); ++ j) {
if(j == q[i].size() - 1) val[q[i][j]] = sum;
else sum ^= (val[q[i][j]] = Random());
}
q[i].clear();
}
int ans = 0, now = 0; p[0] = 1;
rep(i, 1, n) now ^= val[i], ans += p[now], ++ p[now];
rep(i, 1, n) now ^= val[i], p[now] = 0;
printf("%lld\n", ans);
}
return 0;
}

[JXOI2017]颜色的更多相关文章

  1. JXOI2017颜色 解题报告

    JXOI2017颜色 首先记录每个位置上颜色在序列中上次出现的位置 开两颗线段树,第一棵维护区间最大值,实际上是维护当前必须被删去的颜色的位置的最大值,第二棵则是维护区间和 首先倒着扫一遍,对于当前颜 ...

  2. [JXOI2017]颜色 线段树求点对贡献

    [JXOI2017]颜色 题目链接 https://www.luogu.org/problemnew/show/P4065 题目描述 可怜有一个长度为 n 的正整数序列 Ai,其中相同的正整数代表着相 ...

  3. [BZOJ5011][JXOI2017]颜色

    5011: [Jx2017]颜色 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 84  Solved: 46[Submit][Status][Disc ...

  4. 洛谷P4065 [JXOI2017]颜色(线段树)

    题意 题目链接 Sol 线段树板子题都做不出来,真是越来越菜了.. 根据题目描述,一个合法区间等价于在区间内的颜色没有在区间外出现过. 所以我们可以对于每个右端点,统计最长的左端点在哪里,刚开始以为这 ...

  5. JXOI2017颜色

    题面 loj 分析 这道题非常妙啊 对于可保留区间[l, r] 枚举右端点r 考虑l的取值范围有两重约数 记颜色i出现的最右侧位置是\(max_i\) 最左侧位置是\(min_i\) r前最后一次出现 ...

  6. BZOJ5011 JXOI2017颜色(主席树)

    相当于求满足在子段中出现的颜色只在该子段中出现的非空子段数量.这也就相当于其中出现的颜色最左出现的位置在左端点右侧,最右出现的位置在右端点左侧.那么若固定某个端点,仅考虑对该端点的限制,会有一段合法区 ...

  7. 【题解】JXOI2017颜色

    一眼线段树...显然,我们可以考虑最后所留下的区间,那显然这个区间中应当不能存在任何与区间外相同的颜色.这里的转化也是很常用的,我们用 \(nxt[i]\) 表示与 \(i\) 颜色相同的下一个位置在 ...

  8. [JXOI2017]颜色 线段树扫描线 + 单调栈

    ---题面--- 题解: 首先题目要求删除一些颜色,换个说法就是要求保留一些颜色,那么观察到,如果我们设ll[i]和rr[i]分别表示颜色i出现的最左边的那个点和最右边的那个点,那么题目就是在要求我们 ...

  9. BZOJ5011 & 洛谷4065 & LOJ2275:[JXOI2017]颜色——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=5011 https://www.luogu.org/problemnew/show/P4065 ht ...

  10. BZOJ5011 [JXOI2017]颜色 【线段树 + 主席树】

    题目链接 BZOJ5011 题解 一定只有我这种智障会用这么奇怪的方法做这道题.. 由题我们知道最后剩余的一定是一个区间,而且区间内的颜色不存在于区间外 所以我们的目的就是为了找到这样的区间的数量 区 ...

随机推荐

  1. MySQL 体系结构及存储引擎

    MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...

  2. flutter从入门到精通五

    在flutter的世界里,一切都是Widget,图像,文本,布局模型等等,一切都是Widget flutter中,尽量将Widget放在MaterialApp.其封装了所需要的一些Widget,Mat ...

  3. 音视频入门-13-使用开源库生成PNG图片

    * 音视频入门文章目录 * RGB-to-PNG 回顾 上一篇 [手动生成一张PNG图片] 根据 [PNG文件格式详解] 一步一步地手动实现了将 RGB 数据生成了一张 PNG 图片. 有许多开源的 ...

  4. winserver2012远程桌面进入只有CMD窗口,无桌面解决方法

    原因:.net framework4.5是Windows server图形化界面的基础,系统还原时只装了核心模式core,系统没有了图形界面当然只有cmd了   解决方法:使用dism命令需要将核心模 ...

  5. iOS - FMDB数据库的使用

    下面不废话了直接上代码

  6. iOS - 回顾总结Runtime原理及使用

    runtime简介 因为Objc是一门动态语言,所以它总是想办法把一些决定工作从编译连接推迟到运行时.也就是说只有编译器是不够的,还需要一个运行时系统 (runtime system) 来执行编译后的 ...

  7. C# 水仙花数的实现 数据类型

    //int 和int类型计算得到的结果还是int类型 eg:int a = 371 / 100 % 10.一 371除以100得到的是3,而不是3.71.二 再用3%10,求余为3 namespace ...

  8. ios数组倒序

    比如有一个数组: NSArray *arr = @["]; 倒过来排序: arr = [[arr reverseObjectEnumerator] allObjects]; NSMutabl ...

  9. Jmeter学习笔记(四)配置元件之计数器

    在接口测试中,有时候需要重复跑一个接口,里面的某个参数的值不能每次都一样,这个时候我们可以使用计数器来实现,名称+计数器. 1.线程组->添加->配置元件->计数器 2.添加效果如下 ...

  10. 5.JUC之JDK自带锁ReentrantLock

    一.初识 ReentrantLock出身自jdk1.5,中文名:可重入锁 是Java JDK自带独占锁的唯一实现,是synchronized的升级版 1.我们之间有个synchronized 我们已经 ...