[JXOI2017]颜色 线段树扫描线 + 单调栈
题解:
首先题目要求删除一些颜色,换个说法就是要求保留一些颜色,那么观察到,如果我们设ll[i]和rr[i]分别表示颜色i出现的最左边的那个点和最右边的那个点,那么题目就是在要求我们选出的区间要满足区间[l, r]内所有颜色的max(rr[i]) <= r,并且min(ll[i]) >= l. 因为是区间相关的问题,又涉及到左右端点,因此我们考虑扫描线,那么考虑如何维护它。
因为每个颜色的ll[i]和rr[i]可以看做构成了一个区间,那么现在已经进入线段树的节点就分2种情况。
1,区间右端点超过当前右端点:

我们找到离当前右端点最近的点x,使得它代表的区间和右端点关系如上图所示,那么显然这个点x以及它之前的左端点都是不能取的,又因为这个点x是离当前右端点最近的满足条件的点,所以这个点之后都不会因为这个条件而产生冲突,即在这个点后面的,在当前右端点前面的,都满足了右端点的限制。那么我们只需要再满足左端点的限制,然后查询(x, i)对答案的贡献,其中i是当前枚举的右端点。那么我们如何找这个点呢?
观察到一个性质,在后面出现的点的右端点>= 前面出现的点的右端点 的情况下,在后面出现的肯定会更优;因此我们只需要维护一个右端点单调递减的单调栈即可,如果有一个右端点更右出现了,那么肯定会比之前右端点比它小(相等)的点更优,但是不能弹掉右端点比它大的,因为随着右端点的增大,可能这个点就失效了,但之前右端点比它大的点还是有效的。
2,区间右端点不超过当前右端点。

对于这种情况而言,显然我们要么把这个区间全部取了,要么一点都不取。因此不合法的左端点就是(ll, rr],把这段赋0即可。观察到因为我们是赋0,不是-1,所以无法撤销,但是这是没有关系的,因此如果在当前右端点下,这个区间已经不超过它了,那么以后随着右端点的增大,就更不可能超过了,因此不需要撤回。同时也正是因为无法撤回,所以上面那种情况需要单调栈而不是直接修改,因为上面那种情况,随着右端点的增大,是会变成第二种情况的。
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 301000
#define ac 1200100
#define LL long long /*用栈来维护查询的区间(因为每次的区间不同,而且都只要修改前缀,所以完全不用每次修改
(修改了就无法转移到下一个右端点了,因为不满足区间减法,无法撤销),
只需要查询指定区间内的就可以了*/ int n, tot, T;
LL ans;
int ll[AC], rr[AC], color[AC];
int s[AC], top;//栈
int tree[ac], lazy[ac], l[ac], r[ac];//线段树
struct co{
int color, id;
}p[AC]; struct seg{
int l, r;
}line[AC]; bool z[AC]; inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} inline bool cmp1(seg a, seg b)
{
return a.r < b.r;
} inline bool cmp(co a, co b)
{
if(a.color != b.color) return a.color < b.color;
else return a.id < b.id;
} inline void pushdown(int x)
{
if(l[x] != r[x] && lazy[x])
{
int ll = x * , rr = ll + ;
tree[ll] = tree[rr] = lazy[x] = ;
lazy[ll] = lazy[rr] = ;
}
} inline void update(int x)
{
tree[x] = tree[x * ] + tree[x * + ];
} void build(int x, int ll, int rr)
{
l[x] = ll, r[x] = rr, lazy[x] = ;
if(ll == rr) {tree[x] = ; return ;}
int mid = (ll + rr) >> ;
build(x * , ll, mid), build(x * + , mid + , rr);
update(x);
} void change(int x, int ll, int rr)
{
pushdown(x);
if(l[x] == ll && r[x] == rr) {tree[x] = , lazy[x] = ; return ;}
int mid = (l[x] + r[x]) >> ;
if(rr <= mid) change(x * , ll, rr);
else if(ll > mid) change(x * + , ll, rr);
else change(x * , ll, mid), change(x * + , mid + , rr);
update(x);
} void find(int x, int ll, int rr)
{
pushdown(x);
if(l[x] == ll && r[x] == rr){ans += tree[x]; return ;}
int mid = (l[x] + r[x]) >> ;
if(rr <= mid) find(x * , ll, rr);
else if(ll > mid) find(x * + , ll, rr);
else find(x * , ll, mid), find(x * + , mid + , rr);
update(x);
} void pre()
{
n = read();
for(R i = ; i <= n; i ++) color[i] = p[i].color = read(), p[i].id = i;
sort(p + , p + n + , cmp);
for(R i = ; i <= n; i ++)
if(p[i].color != p[i - ].color)
rr[p[i - ].color] = p[i - ].id, ll[p[i].color] = p[i].id;
rr[p[n].color] = p[n].id;
for(R i = ; i <= n; i ++)
if(ll[i]) line[++tot] = (seg){ll[i], rr[i]};
sort(line + , line + tot + , cmp1);
} void init()
{
memset(ll, , sizeof(ll)), memset(rr, , sizeof(rr));
tot = ans = top = ;
} void get()
{
int l = ;
for(R i = ; i <= n; i ++)//不断扩大右端点
{
//printf("!!!%d\n", i);
while(top && rr[color[i]] >= rr[color[s[top]]]) -- top;//如果一个点在栈顶右侧,且右端点大于等于栈顶,那么它肯定更优。
s[++top] = i;//栈里面存颜色就够了, ,,,不,,,还是需要存下标
while(top && rr[color[s[top]]] <= i) -- top;//去掉不合法的情况
for(; line[l].r <= i && l <= tot; ++ l)//error!!!这里要用tot,不然的话用n可能会用到一些未被覆盖的,来自前面的数据的区间
if(line[l].l < line[l].r) change(, line[l].l + , line[l].r);
if(s[top] + <= i) find(, s[top] + , i); //要有合法的情况才查询,否则没有必要查询
}
printf("%lld\n", ans);
} void work()
{
T = read();
while(T --) init(), pre(), build(, , n), get();
} int main()
{
// freopen("color7.in", "r", stdin);
work();
// fclose(stdin);
return ;
}
[JXOI2017]颜色 线段树扫描线 + 单调栈的更多相关文章
- [CSP-S模拟测试]:陶陶摘苹果(线段树维护单调栈)
题目传送门(内部题116) 输入格式 第一行两个整数$n,m$,如题 第二行有$n$个整数表示$h_1-h_n(1\leqslant h_i\leqslant 10^9)$ 接下来有$m$行,每行两个 ...
- Wannafly挑战赛18 E 极差(线段树、单调栈)
Wannafly挑战赛18 E 极差 题意 给出三个长度为n的正整数序列,一个区间[L,R]的价值定义为:三个序列中,这个区间的极差(最大值与最小值之差)的乘积. 求所有区间的价值之和.答案对\(2^ ...
- HDU 5875 Function (线段树+gcd / 单调栈)
题意:给你一串数a再给你一些区间(lef,rig),求出a[lef]%a[lef+1]...%a[rig] 题解:我们可以发现数字a对数字b取模时:如果a<b,则等于原数,否则a会变小至少一半. ...
- Educational Codeforces Round 61 (Rated for Div. 2) G(线段树,单调栈)
#include<bits/stdc++.h>using namespace std;int st[1000007];int top;int s[1000007],t[1000007];i ...
- [BZOJ 2957]楼房重建(THU2013集训)(线段树维护单调栈)
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2957 分析: 根据题意,就是比较斜率大小 只看一段区间的话,那么这段区间能看见的楼房数量就是这 ...
- 洛谷P4065 [JXOI2017]颜色(线段树)
题意 题目链接 Sol 线段树板子题都做不出来,真是越来越菜了.. 根据题目描述,一个合法区间等价于在区间内的颜色没有在区间外出现过. 所以我们可以对于每个右端点,统计最长的左端点在哪里,刚开始以为这 ...
- 洛谷 P4198 楼房重建 线段树维护单调栈
P4198 楼房重建 题目链接 https://www.luogu.org/problemnew/show/P4198 题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上 ...
- [CSP-S模拟测试]:God Knows(线段树维护单调栈)
题目描述 小$w$来到天堂的门口,对着天堂的大门发呆.大门上有一个二分图,左边第$i$个点连到右边第$p_i$个点.(保证$p_i$是一个排列).小$w$每次可以找左边某个对应连线尚未被移除的点$i$ ...
- 洛谷P3246 序列 [HNOI2016] 莫队/线段树+扫描线
正解:莫队/线段树+扫描线 解题报告: 传送门! 似乎是有两种方法的,,,所以分别港下好了QAQ 第一种,莫队 看到这种询问很多区间之类的就会自然而然地想到莫队趴?然后仔细思考一下,发现复杂度似乎是欧 ...
随机推荐
- 低于0.01%的极致Crash率是怎么做到的?
WeTest 导读 看似系统Bug的Crash 99%都不是系统问题!本文将与你一起探索Crash分析的科学方法. 在移动互联网闯荡多年的iOS手机管家,经过不断迭代创新,已经涵盖了隐私(加密相册). ...
- python一标准异常总结大全(非常全)
Python标准异常总结 AssertionError 断言语句(assert)失败 AttributeError 尝试访问未知的对象属性 EOFError 用户输入文件末尾标志EOF(Ctrl+d) ...
- hackerrank Project Euler #210: Obtuse Angled Triangles
传送门 做出一个好几个星期屯下来的题目的感觉就是一个字: 爽! 上图的黄点部分就是我们需要求的点 两边的部分很好算 求圆的地方有一个优化,由于圆心是整数点,我们可以把圆分为下面几个部分,阴影部分最难算 ...
- Java开发工程师(Web方向) - 03.数据库开发 - 第4章.事务
第4章--事务 事务原理与开发 事务Transaction: 什么是事务? 事务是并发控制的基本单位,指作为单个逻辑工作单元执行的一系列操作,且逻辑工作单元需满足ACID特性. i.e. 银行转账:开 ...
- Spring 配置请求过滤器,编码格式设为UTF-8,避免中文乱码
<!-- 配置请求过滤器,编码格式设为UTF-8,避免中文乱码--> <filter> <filter-name>springUtf8Encoding</fi ...
- python切片技巧
写一个程序,打印数字1到100,3的倍数打印“Fizz”来替换这个数,5的倍数打印“Buzz”,对于既是3的倍数又是5的倍数的数字打印“FizzBuzz” for x in range(101): p ...
- 试用Markdown来写东西
试用Markdown来写东西 前言 之前有过一段时间的写东西的习惯,但是后来因为各种原因(主要是因为自己懒惰拖延),所以一直没有写,现在想再开始写,目的很明确,就是发现很多时候,写作能够很好的练习自己 ...
- 关于mysql开元数据库的几个随想
现在已经是凌晨了,昨天晚上写了我人生中的第一篇笔记,觉得没什么可写的,写了一个多小时都没写出什么,现在突然想写点东西了,这是一个比较有趣的问题,前两个月换了新工作,记得当初面试这份工作的时候面试到第三 ...
- 【转载】图解Java常用数据结构(一)
图解Java常用数据结构(一) 作者:大道方圆 原文:https://www.cnblogs.com/xdecode/p/9321848.html 最近在整理数据结构方面的知识, 系统化看了下Jav ...
- UVALive 3668 A Funny Stone Game(博弈)
Description The funny stone game is coming. There are n piles of stones, numbered with 0, 1, 2,..., ...