【vijos】1881 闪烁的繁星(线段树+特殊的技巧)

https://vijos.org/p/1881

这场比赛太难了sad。所以我都没做。。

这题一开始我竟然不会sad(本来就不会),然后我继续yy。。yy了好久,竟然yy了个什么可拆分的并查集?(sad,后来发现我是如此sb,根本无法实现。。)

然后我弃疗了,比赛干脆不交了。。sad

后来看了题解和神犇们热心的指导,这就是一水题。。

sad。

我们只需要在线段树维护三个值,L表示这个节点的区间内从左边向又能延伸的最长可行串的长度,R表示这个节点的区间内从右边向左能延伸的最长可行串的长度,mx表示这个区间最长的可行串的长度。

那么我们在pushup里面只需要这样转移即可

void pushup(int x, int len) {
	int l=lc, r=rc;
	t[x].x=t[l].x;
	t[x].y=t[r].y;
	t[x].lx=t[l].lx;
	t[x].rx=t[r].rx;
	t[x].mx=max(t[l].mx, t[r].mx);
	if(t[l].y!=t[r].x) {
		t[x].mx=max(t[x].mx, t[l].rx+t[r].lx);
		if(t[l].mx==(len-(len>>1))) t[x].lx=max(t[x].lx, t[l].mx+t[r].lx);
		if(t[r].mx==(len>>1)) t[x].rx=max(t[x].rx, t[r].mx+t[l].rx);
	}
}

这个多想想就知道为什么了。。。(因为我是蒟蒻所以我想不出来。orz

然后这题就成为水题了。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
#define printarr1(a, b) for1(_, 1, b) cout << a[_] << ‘\t‘; cout << endl
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<‘0‘||c>‘9‘; c=getchar()) if(c==‘-‘) k=-1; for(; c>=‘0‘&&c<=‘9‘; c=getchar()) r=r*10+c-‘0‘; return k*r; }
inline const int max(const int &a, const int &b) { return a>b?a:b; }
inline const int min(const int &a, const int &b) { return a<b?a:b; }
const int N=200005;
#define lc x<<1
#define rc x<<1|1
#define lson l, m, lc
#define rson m+1, r, rc
#define MID (l+r)>>1

struct dat { int lx, rx, x, y, mx; }t[N<<2];
int n, Q;
void pushup(int x, int len) {
	int l=lc, r=rc;
	t[x].x=t[l].x;
	t[x].y=t[r].y;
	t[x].lx=t[l].lx;
	t[x].rx=t[r].rx;
	t[x].mx=max(t[l].mx, t[r].mx);
	if(t[l].y!=t[r].x) {
		t[x].mx=max(t[x].mx, t[l].rx+t[r].lx);
		if(t[l].mx==(len-(len>>1))) t[x].lx=max(t[x].lx, t[l].mx+t[r].lx);
		if(t[r].mx==(len>>1)) t[x].rx=max(t[x].rx, t[r].mx+t[l].rx);
	}
}
void build(int l, int r, int x) {
	t[x].mx=t[x].x=t[x].y=t[x].lx=t[x].rx=1;
	if(l==r) return;
	int m=MID;
	build(lson); build(rson);
}
void upd(int l, int r, int x, int p) {
	if(l==r) { t[x].x=t[x].y=!t[x].x; return; }
	int m=MID;
	if(p<=m) upd(lson, p); else upd(rson, p);
	pushup(x, r-l+1);
}
int main() {
	read(n); read(Q);
	build(1, n, 1);
	while(Q--) {
		upd(1, n, 1, getint());
		printf("%d\n", t[1].mx);
	}
	return 0;
}

背景

繁星闪烁着--深蓝的太空
何曾听得见他们对语
沉默中
微光里
他们深深的互相颂赞了

描述

繁星, 漫天的繁星.
繁星排成一列, 我数一数呀, 一共有N只小星星呢.

星星们是听话的好孩子, 小岛在指挥它们跳舞呢.
舞蹈开始前, 它们都亮了起来!

小岛指一指第i只小星星, 只见第i只小星星立刻改变了自己的状态.
如果它之前是亮着的, 那么立刻就灭掉了.
如果它之前是灭掉的, 现在就立刻亮了呀!

如果说, 可以有连续若干只小星星.
其中任意相邻两只星星状态不同.
那就是最美的了.

小岛希望知道:
每一次发出指令之后
能找到最长的连续小星星, 满足上述需求的
有多长?

格式

输入格式

第一行有两个整数, 分别为星星总数N, 和指令总数Q.
1<=N<=200,000; 1<=Q<=200,000.
之后Q行, 每行有一个整数i: 1<=i<=N, 表示小岛发出的指令.

输出格式

输出有Q行, 其中每i行有一个整数.
表示小岛的第i条指令发出之后, 可以找到的满足要求的最长连续星星序列有多长?

样例1

样例输入1[复制]

6 2
2
4

样例输出1[复制]

3
5

限制

对于20%的数据: N, Q <= 100.
对于30%的数据: N, Q <= 70000.
对于100%的数据: 1 <= N, Q <= 200,000.

提示

对于样例, 星星序列的状态依次为: OOOOOO -> OXOOOO -> OXOXOO
这里用O表示亮着的星星, 用X表示灭掉的星星.

时间: 2024-10-28 05:20:11

【vijos】1881 闪烁的繁星(线段树+特殊的技巧)的相关文章

Vijos1881闪烁的繁星 [线段树]

P1881闪烁的繁星 背景 繁星闪烁着--深蓝的太空何曾听得见他们对语沉默中微光里他们深深的互相颂赞了 描述 繁星, 漫天的繁星.繁星排成一列, 我数一数呀, 一共有N只小星星呢. 星星们是听话的好孩子, 小岛在指挥它们跳舞呢.舞蹈开始前, 它们都亮了起来! 小岛指一指第i只小星星, 只见第i只小星星立刻改变了自己的状态.如果它之前是亮着的, 那么立刻就灭掉了.如果它之前是灭掉的, 现在就立刻亮了呀! 如果说, 可以有连续若干只小星星.其中任意相邻两只星星状态不同.那就是最美的了. 小岛希望知道

POJ2528Mayor&#39;s posters 线段树,离散化技巧

题意:一个坐标轴从1~1e7,每次覆盖一个区间(li,ri),问最后可见区间有多少个(没有被其他区间挡住的) 线段树,按倒序考虑,贴上的地方记为1,每次看(li,ri)这个区间是否全是1,全是1就说明在它后面贴的把它给挡住了,否则该海报可见. 然后就愉快的MLE了.... 再看看数据范围,离散化如下,比如如果海报的左右端点如下 那图中橙色的一块的大小其实对结果没有影响,可以把他们都缩为1 最后离散化结果如下图: 代码: 1 #include <algorithm> 2 #include <

Vijos P1881 闪烁的繁星

P1882石阶上的砖 标签:d[显示标签] 背景 微雨的山门下 石阶湿着-- 只有独立的我 和缕缕的游云 这也是'同参密藏'么 描述 清晨, Alice与Bob在石阶上玩砖块. 他们每人都有属于自己的一堆砖块. 每人的砖块都由N列组成且N是奇数. Alice的第i列砖块有m[i]个. 而Bob的第i列砖块有s[i]个. 他们想建造城堡, 两座一样的城堡. 每一座城堡都是从正中间一列开始: 1)若往左侧看去,数量逐次增加,每一列都比右侧的一列多出恰一块砖. 2)若往右侧看去,数量逐次增加,每一列都

Vijos 1083 小白逛公园(线段树)

线段树,每个结点维护区间内的最大值M,和sum,最大前缀和lm,最大后缀和rm. 若要求区间为[a,b],则答案max(此区间M,左儿子M,右儿子M,左儿子rm+右儿子lm). --------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<

【POJ】2828 Buy Tickets(线段树+特殊的技巧/splay)

http://poj.org/problem?id=2828 一开始敲了个splay,直接模拟. tle了.. 常数太大.. 好吧,说是用线段树.. 而且思想很拽.. (貌似很久以前写过貌似的,,) 我们线段树维护的区间不再是人了.. 而是这个区间剩余的的座位.. 比如我现在要坐第一张,但是人已经坐了,即这个区间已经没有位置了..那就要往后坐. 所以我们逆序添加,,因为后来人插队前边人管不着... 所以后来人一定是先定座位的.. 每一次维护这个座位区间.. 如果左边这个区间座位比我要坐的座位号要

【BZOJ】3339: Rmq Problem &amp; 3585: mex(线段树+特殊的技巧)

http://www.lydsy.com/JudgeOnline/problem.php?id=3585 好神的题. 但是!!!!!!!!!!!!!!我线段树现在要开8倍空间才能过!!!!!!!!!!这什么梗...................... 我思考了很久空间的问题,因为我在pushdown的时候可能会越界,或许是pushup? 不管了.然后看了zyf的写法.看来以后得注意下...pushdown弄成先放了... 本题的做法: 好神orz 首先像莫队一样离线区间,左端点在前. 考虑如何

Vijos P1881 闪烁的繁星 (自己加强了一下。。)

如果每一次查询的不是整个长度,而是[x, y]这个区间..闲来无事自己写了一下,感觉是对的,这样就变成了合并区间. #include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <queue> #include <algorithm> #define mem(f) memset(f,0,sizeof(f)) #define M 10

小结:线段树 &amp; 主席树

概要: 就是用来维护区间信息,然后各种秀智商游戏. 应用: 优化dp.主席树等. 技巧及注意: size值的活用:主席树就是这样来的.支持区间加减,例题和模板:主席树,[BZOJ]1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树),[BZOJ]1901: Zju2112 Dynamic Rankings(区间第k小+树状数组套可持久化线段树(主席树)) 01(就是更新和不更新等这种对立操作)情况:我们就要在各个更新的操作中明白

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击