【题解】JXOI2017颜色
一眼线段树...显然,我们可以考虑最后所留下的区间,那显然这个区间中应当不能存在任何与区间外相同的颜色。这里的转化也是很常用的,我们用 \(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颜色的更多相关文章
- [JXOI2017]颜色 线段树求点对贡献
[JXOI2017]颜色 题目链接 https://www.luogu.org/problemnew/show/P4065 题目描述 可怜有一个长度为 n 的正整数序列 Ai,其中相同的正整数代表着相 ...
- JXOI2017颜色 解题报告
JXOI2017颜色 首先记录每个位置上颜色在序列中上次出现的位置 开两颗线段树,第一棵维护区间最大值,实际上是维护当前必须被删去的颜色的位置的最大值,第二棵则是维护区间和 首先倒着扫一遍,对于当前颜 ...
- BZOJ5011 & 洛谷4065 & LOJ2275:[JXOI2017]颜色——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5011 https://www.luogu.org/problemnew/show/P4065 ht ...
- [JXOI2017]颜色 线段树扫描线 + 单调栈
---题面--- 题解: 首先题目要求删除一些颜色,换个说法就是要求保留一些颜色,那么观察到,如果我们设ll[i]和rr[i]分别表示颜色i出现的最左边的那个点和最右边的那个点,那么题目就是在要求我们 ...
- [BZOJ5011][JXOI2017]颜色
5011: [Jx2017]颜色 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 84 Solved: 46[Submit][Status][Disc ...
- BZOJ5011 [JXOI2017]颜色 【线段树 + 主席树】
题目链接 BZOJ5011 题解 一定只有我这种智障会用这么奇怪的方法做这道题.. 由题我们知道最后剩余的一定是一个区间,而且区间内的颜色不存在于区间外 所以我们的目的就是为了找到这样的区间的数量 区 ...
- [JXOI2017]颜色
\(Orz\) 各位题解大佬,我来膜拜一发 还有单调栈实在没弄懂 法一:线段树+堆 首先,讨论区间的个数的题目,我们可以想到枚举一个端点\(r\),找到所有的\(l\) 我们不妨设:\(ml[i]\) ...
- 洛谷P4065 [JXOI2017]颜色(线段树)
题意 题目链接 Sol 线段树板子题都做不出来,真是越来越菜了.. 根据题目描述,一个合法区间等价于在区间内的颜色没有在区间外出现过. 所以我们可以对于每个右端点,统计最长的左端点在哪里,刚开始以为这 ...
- JXOI2017颜色
题面 loj 分析 这道题非常妙啊 对于可保留区间[l, r] 枚举右端点r 考虑l的取值范围有两重约数 记颜色i出现的最右侧位置是\(max_i\) 最左侧位置是\(min_i\) r前最后一次出现 ...
随机推荐
- VIO概述 On-Manifold Preintegration for Real-Time Visual--Inertial Odometry
目前的研究方向可以总结为在滤波算法中实现高精度,在优化算法中追求实时性.当加入IMU后,研究方向分为松耦合和紧耦合,松耦合分别单独计算出IMU测量得到的状态和视觉里程计得到的状态然后融合,紧耦合则将I ...
- 「赛后补题」Meeting(HDU-5521)
题意 A,B两个人分别在1和n区.每个区有若干点(区之间的点可以重复,各个区内点间的距离一致),给出区之间有联系的图以及到达所需时间.求两个人见面最短时间以及在哪个区碰面(可有多个) 分析 隐式图搜索 ...
- uvaoj 489 - Hangman Judge(逻辑+写代码能力)
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- MySQL日期、字符串、时间戳互转
平时比较常用的时间.字符串.时间戳之间的互相转换,虽然常用但是几乎每次使用时候都喜欢去搜索一下用法:本文将作为一个笔记,整理一下三者之间的 转换(即:date转字符串.date转时间戳.字符串转dat ...
- PHP使用Redis消息队列
1.redis安装 参考:菜鸟教程http://www.runoob.com/redis/redis-install.html 2.安装php的redis扩展 1)phpinfo()查看php版本信息 ...
- Selenium(Python)调用pywin32上传图片
import unittestfrom time import sleep import osfrom selenium import webdriverimport win32apiimport w ...
- Linux命令应用大词典-第18章 磁盘分区
18.1 fdisk:分区表管理 18.2 parted:分区维护程序 18.3 cfdisk:基于磁盘进行分区操作 18.4 partx:告诉内核关于磁盘上分区的号码 18.5 sfdisk:用于L ...
- (C#)工厂方法模式
1.工厂方法模式 第一了一个用于创建对象的接口,让子类自己决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. *工厂方法模式即克服了简单工厂模式违反开放-封闭原则的缺点,又保留了封装对象创建过 ...
- Java 集合学习--HashMap
一.HashMap 定义 HashMap 是一个基于散列表(哈希表)实现的键值对集合,每个元素都是key-value对,jdk1.8后,底层数据结构涉及到了数组.链表以及红黑树.目的进一步的优化Has ...
- 小球下落 (Dropping Balls,UVA 679)
题目描述: 题目思路: 1.直接用数组模拟二叉树下落过程 //超时 #include <iostream> #include <cstring> using namespace ...