一眼线段树...显然,我们可以考虑最后所留下的区间,那显然这个区间中应当不能存在任何与区间外相同的颜色。这里的转化也是很常用的,我们用 \(nxt[i]\) 表示与 \(i\) 颜色相同的下一个位置在哪里, \(last[i]\) 表示与 \(i\) 颜色相同的上一个位置在哪里;那么一个区间 \(i, j\) 是满足要求的当且仅当 \(min(last[k]) >= i, max(nxt[k]) <= j (i <= k  <= j)\) 。我们可以用单调栈处理出 \(lim[i]\) 记录下第一个 \(last[k] < i (k >= i)\) 的 \(k\)。那么我们可以发现以 \(i\) 为区间左端点的区间右端点一定在 \([i, lim[i] - 1]\) 之间。我们考虑如何满足有关 \(j\) 的限制。

  我们由于左端点是从右往左的扫描线,所以考虑答案的时候也只需要考虑当前 \(>= i\) 的 \(j\) (满足当前考虑的限制均是在 \([i, n]\) 范围内的限制)。由于 \(max(nxt[k]) <= j\) ,所以对于所有的 \(k\) 与 \(nxt[k]\) 而言,它所影响到的右端点就是在 \([k, nxt[k] - 1]\) 范围内的节点,让他们都无法与之后所有的左端点匹配成为合法的区间。我们只需要维护一棵每碰到限制就区间赋值为 \(0\)的线段树 ,并查询区间内的总和就可以计算出合法的区间总数啦。

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000000
#define LL long long
#define INF 99999999999LL
int n, a[maxn], rec[maxn], mark[maxn];
int top, S[maxn], nxt[maxn], last[maxn], lim[maxn];
int sum[maxn]; LL ans; int read()
{
int x = , k = ;
char c; c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void Push_down(int p)
{
if(!mark[p]) return;
int ls = p << , rs = p << | ;
mark[ls] = mark[rs] = ; sum[ls] = sum[rs] = ;
mark[p] = ;
} int Query(int p, int l, int r, int L, int R)
{
if(L > R) return ;
if(L > r || R < l) return ;
if(L <= l && R >= r) return sum[p];
int mid = (l + r) >> ;
Push_down(p);
return Query(p << , l, mid, L, R) + Query(p << | , mid + , r, L, R);
} void Update(int p, int l, int r, int L, int R)
{
if(L > r || R < l) return;
if(L <= l && R >= r) { mark[p] = , sum[p] = ; return; }
int mid = (l + r) >> ;
Push_down(p);
Update(p << , l, mid, L, R), Update(p << | , mid + , r, L, R);
sum[p] = sum[p << ] + sum[p << | ];
} void Build(int p, int l, int r)
{
if(l == r) { sum[p] = ; return; }
int mid = (l + r) >> ;
Build(p << , l, mid), Build(p << | , mid + , r);
sum[p] = sum[p << ] + sum[p << | ];
} void init()
{
memset(mark, , sizeof(mark));
memset(rec, , sizeof(rec));
ans = ;
} signed main()
{
int T = read();
while(T --)
{
init(); n = read();
for(int i = ; i <= n; i ++) a[i] = read();
for(int i = ; i <= n; i ++)
{
last[i] = nxt[i] = ;
last[i] = rec[a[i]], nxt[rec[a[i]]] = i;
rec[a[i]] = i;
}
for(int i = ; i <= n; i ++)
if(!last[i]) last[i] = n + ;
for(int i = n; i >= ; i --)
{
while(top >= && last[S[top]] > last[i]) top --;
S[++ top] = i;
while(top >= && last[S[top]] >= i) top --;
if(!top) lim[i] = n + ;
else lim[i] = S[top];
}
Build(, , n);
for(int i = n; i >= ; i --)
{
if(nxt[i]) Update(, , n, i, nxt[i] - );
ans += (LL) Query(, , n, i, lim[i] - );
}
printf("%lld\n", ans);
}
return ;
}

【题解】JXOI2017颜色的更多相关文章

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

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

  2. JXOI2017颜色 解题报告

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

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

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

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

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

  5. [BZOJ5011][JXOI2017]颜色

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

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

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

  7. [JXOI2017]颜色

    \(Orz\) 各位题解大佬,我来膜拜一发 还有单调栈实在没弄懂 法一:线段树+堆 首先,讨论区间的个数的题目,我们可以想到枚举一个端点\(r\),找到所有的\(l\) 我们不妨设:\(ml[i]\) ...

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

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

  9. JXOI2017颜色

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

随机推荐

  1. Android stdio build.gradle buildscript 里面的repositories 和allprojects里面 repositories 的区别

    第一段 buildscript 里面的 repositories 表示只有编译工具才会用这个仓库. 比如 buildscript 里面的 dependencies classpath 'com.and ...

  2. 破解IDEA注册码,设置 license server一直有效不过期

    破解的详细过程: 1.从下面地址下载一个jar包,名称是  JetbrainsCrack-2.10-release-enc.jar 下载地址是http://idea.lanyus.com/,进去之后点 ...

  3. 游戏AI之群组行为

    群组行为指的是多个对象组队同时进行的情况.每个boid需满足分离,队列,凝聚三个基本的规则. 分离:群组中的每个个体都与相邻的个体保持一定的距离. 队列:群组以相同的速度,向相同的方向移动. 凝聚:与 ...

  4. C# 中访问修饰符

    1.public 完全公开的,公共的 2. private 私有的,只能在当前类的内部访问, 不可修饰类 3.protected 受保护的,只能在当前类的内部以及其子类中访问,不能用来修饰类 4.in ...

  5. 157. Unique Characters 【LintCode by java】

    Description Implement an algorithm to determine if a string has all unique characters. Example Given ...

  6. (python)leetcode刷题笔记04 Median of Two Sorted Arrays

    4. Median of Two Sorted Arrays There are two sorted arrays nums1 and nums2 of size m and n respectiv ...

  7. Java进阶知识点:不可变对象与并发

    一.String的不可变特性 熟悉Java的朋友都知道,Java中的String有一个很特别的特性,就是你会发现无论你调用String的什么方法,均无法修改this对象的状态.当确实需要修改Strin ...

  8. 水管工游戏:dfs(递归)

    添柴网这题好想不能评测,所以不确保代码的正确性 题目描述: 这小节有点难,看不太懂可以跳过哦.最近小哼又迷上一个叫做水管工的游戏.游戏的大致规则是这样的.一块矩形土地被分为N * M的单位正方形,现在 ...

  9. [转载]Tensorflow中reduction_indices 的用法

    Tensorflow中reduction_indices 的用法 默认时None 压缩成一维

  10. Python实现个性化推荐二

    基于内容的推荐引擎是怎么工作的 基于内容的推荐系统,正如你的朋友和同事预期的那样,会考虑商品的实际属性,比如商品描述,商品名,价格等等.如果你以前从没接触过推荐系统,然后现在有人拿枪指着你的头,强迫你 ...