P2572 [SCOI2010]序列操做

写在前面

傻逼线段树题,码量第一次超 \(6.5k\)ios

由于不能考 \(NOIp\) 一气之下把它肝了(放屁,你是由于想看小说,而作数据结构不用脑子,好在DJ来的时候方便掩饰数据结构

我的感受理解本题后会对线段树有更为深入的理解,亦可增长对线段树的套路用法,了解各操做之间的优先级ui

本题解陈述尽可能详细周全,如有赘述的地方请自行跳过,若是有什么疑问也可在评论区提出spa

简述题意

题面code

给定一段 \(01\) 序列,有 \(5\) 种操做get

0、一段区间变成 \(0\)
一、一段区间变成 \(1\)
二、对一段区间取反
三、询问一段区间内有多少个 \(1\)
四、询问一段区间内最多有多少个连续的 \(1\)string

序列长为 \(n\) ,有 \(m\) 个操做(数据范围:\(1 \le n,m\le 10^5\)it

Solution

操做 \(0,1,3\) 都比较好解决,线段树基本操做,这里不赘述io

主要是 \(2,4\) 操做class

对于 \(4\) 操做,咱们不难想到能够用 \(max\) 维护区间最长的 \(1\) ,分别用 \(lmax\)\(rmax\) 来维护左端点最长的 \(1\) 和右端点最长的 \(1\)

在上传是注意 \(max\) 要和左右儿子的 \(max\) ,以及左儿子的 \(rmax\) 加右儿子的 \(lmax\) 这三个值中取最大值

(相信作过 GSS3 都能直接想到 \(4\) 的处理方法,没作过也没有关系,思路应该也是比较好理解的)

那加上 \(2\) 操做怎么融合,另设一个懒标记 \(rev\) 来表示是否翻转

一、由于有两种修改操做,考虑懒标记优先级:由于 \(0, 1\) 的操做会把取反操做覆盖掉,因此覆盖的优先级要高于反转的优先级

二、只有一个 \(max,lmax,rmax\),每次翻转后怎么更新:直接设两个不就行了,把 \(0, 1\)\(max, lmax, rmax\) 都存下来,翻转的时候只要交换就行了

三、翻转后如何求和:这个比较简单,用长度减掉原来的 \(sum\) 就行了

在询问 \(4\) 操做时,要注意两端序列的合并应使用结构体回传(好像较为复杂的线段树题都须要这样处理)

由于最后的答案多是由两段区间合并而成

code

洛谷code

因为码量较大,请注意保护眼睛

尽量的作到了排版整齐,变量名称清新易懂,过程简洁明了,还附有必定的注释来帮助理解

能够考虑用循环减小码量,但我感受拆开写更方便理解(善用位运算能够省很多力)

(感谢_wzd提出在4操做中回传有关0的 \(max,lmax,rmax\) 没有意义,所以能够省略)

/*
Work by: Suzt_ilymics
Knowledge: 傻逼线段树 
Time: O(??)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lson i << 1
#define rson i << 1 | 1
#define orz cout<<"lkp ak ioi"<<endl;

using namespace std;
const int MAXN = 1e5+5;
const int INF = 1;
const int mod = 1;

struct Tree{
	int len, lazy, sum, lmax[2], rmax[2], max[2], rev;
}tree[MAXN << 2];
 
int n, m;
int a[MAXN];

int read(){
	int s = 0, w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
	return s * w;
}

int max(int x, int y){ return x > y ? x : y; }

void push_up(int i){//上传
	tree[i].sum = tree[lson].sum + tree[rson].sum;//维护区间和 
	
	if(tree[lson].sum == tree[lson].len) tree[i].lmax[1] = tree[lson].lmax[1] + tree[rson].lmax[1];//维护	 
	else 				     tree[i].lmax[1] = tree[lson].lmax[1]; 
	if(tree[rson].sum == tree[rson].len) tree[i].rmax[1] = tree[rson].rmax[1] + tree[lson].rmax[1];
	else                                 tree[i].rmax[1] = tree[rson].rmax[1]; 
	tree[i].max[1] = max(tree[lson].max[1], tree[rson].max[1]);//维护区间最多有的连续的1,取左区间最大值、右区间最大值、左区间右边最大值和右区间左边最大值的和三个中的最大值 
	tree[i].max[1] = max(tree[i].max[1],    tree[lson].rmax[1] + tree[rson].lmax[1]);
	
	if(tree[lson].sum == 0) tree[i].lmax[0] = tree[lson].lmax[0] + tree[rson].lmax[0];//维护	 
	else 			tree[i].lmax[0] = tree[lson].lmax[0]; 
	if(tree[rson].sum == 0) tree[i].rmax[0] = tree[rson].rmax[0] + tree[lson].rmax[0];
	else 			tree[i].rmax[0] = tree[rson].rmax[0]; 
	tree[i].max[0] = max(tree[lson].max[0], tree[rson].max[0]);//维护区间最多有的连续的0,取左区间最大值、右区间最大值、左区间右边最大值和右区间左边最大值的和三个中的最大值 
	tree[i].max[0] = max(tree[i].max[0],    tree[lson].rmax[0] + tree[rson].lmax[0]);
	return ;
}

void build(int i, int l, int r){
	tree[i].len = r - l + 1, tree[i].lazy = -1, tree[i].rev = 0; 
	if(l == r) {
		tree[i].sum = a[l];
		tree[i].max[0] = tree[i].lmax[0] = tree[i].rmax[0] = (a[l] == 0);
		tree[i].max[1] = tree[i].lmax[1] = tree[i].rmax[1] = (a[l] == 1);
		return ;
	}
	int mid = (l + r) >> 1;
	build(lson, l, mid), build(rson, mid + 1, r);
	push_up(i);
	return ;
}

void push_down(int i){//下穿,注意优先级
	if(tree[i].lazy != -1){
		tree[i].rev = 0;
		int val = tree[i].lazy;
		tree[lson].sum = tree[lson].len * val;
		tree[rson].sum = tree[rson].len * val;
		
		tree[lson].lazy = tree[rson].lazy = val;
		tree[lson].rev = tree[rson].rev = 0;
		
		tree[lson].lmax[val ^ 1] = tree[lson].rmax[val ^ 1] = tree[lson].max[val ^ 1] = 0;
		tree[rson].lmax[val ^ 1] = tree[rson].rmax[val ^ 1] = tree[rson].max[val ^ 1] = 0;
		tree[lson].lmax[val] = tree[lson].rmax[val] = tree[lson].max[val] = tree[lson].len;
		tree[rson].lmax[val] = tree[rson].rmax[val] = tree[rson].max[val] = tree[rson].len;
		
		tree[i].lazy = -1;
	}
	if(tree[i].rev){
		tree[lson].sum = tree[lson].len - tree[lson].sum;
		tree[rson].sum = tree[rson].len - tree[rson].sum;
		
		if(tree[lson].lazy != -1) tree[lson].lazy ^= 1;
		else tree[lson].rev ^= 1;
		if(tree[rson].lazy != -1) tree[rson].lazy ^= 1;
		else tree[rson].rev ^= 1;
		
		swap(tree[lson].max[0], tree[lson].max[1]);
		swap(tree[lson].lmax[0], tree[lson].lmax[1]);
		swap(tree[lson].rmax[0], tree[lson].rmax[1]);
		
		swap(tree[rson].max[0], tree[rson].max[1]);
		swap(tree[rson].lmax[0], tree[rson].lmax[1]);
		swap(tree[rson].rmax[0], tree[rson].rmax[1]);
		
		tree[i].rev = 0;
	}
	return ;
}

void change01(int i, int l, int r, int L, int R, int k){//01覆盖操做
	push_down(i);
	if(L <= l && r <= R){
		tree[i].sum = tree[i].len * k;
		tree[i].lazy = k;
		tree[i].lmax[k] = tree[i].rmax[k] = tree[i].max[k] = tree[i].len;
		tree[i].lmax[k ^ 1] = tree[i].rmax[k ^ 1] = tree[i].max[k ^ 1] = 0;
		return ;
	}
	int mid = (l + r) >> 1;
	if(mid < L) change01(rson, mid + 1, r, L, R, k);
	else if(mid >= R) change01(lson, l, mid, L, R, k);
	else change01(lson, l, mid, L, mid, k), change01(rson, mid + 1, r, mid + 1, R, k);
	push_up(i);
}

void changef(int i, int l, int r, int L, int R){//取反操做
	push_down(i);
	if(L <= l && r <= R){
		tree[i].sum = tree[i].len - tree[i].sum;
		tree[i].rev ^= 1;
		swap(tree[i].max[1],  tree[i].max[0]);
		swap(tree[i].lmax[1], tree[i].lmax[0]);
		swap(tree[i].rmax[1], tree[i].rmax[0]);
		return ;
	}
	int mid = (l + r) >> 1;
	if(mid < L) changef(rson, mid + 1, r, L, R);
	else if(mid >= R) changef(lson, l, mid, L, R);
	else changef(lson, l, mid, L, mid), changef(rson, mid + 1, r, mid + 1, R);
	push_up(i);
}

int get_sum(int i, int l, int r, int L, int R){//区间和
	push_down(i);
	if(L <= l && r <= R){
		return tree[i].sum;
	}
	int mid = (l + r) >> 1, ans = 0;
	if(mid < L) return get_sum(rson, mid + 1, r, L, R);
	else if(mid >= R) return  get_sum(lson, l, mid, L, R);
	else return get_sum(lson, l, mid, L, mid) + get_sum(rson, mid + 1, r, mid + 1, R);
}

Tree get_max(int i, int l, int r, int L, int R){//区间最大值
//	cout<<i<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<endl;
	push_down(i);
	if(L <= l && r <= R){ return tree[i]; }
	int mid = (l + r)>> 1;
	if(mid < L) return get_max(rson, mid + 1, r, L, R);
	else if(mid >= R) return get_max(lson, l, mid, L, R);
	else {
		Tree ans, ansl = get_max(lson, l, mid, L, mid), ansr = get_max(rson, mid + 1, r, mid + 1, R);
		ans.sum = ansl.sum + ansr.sum;
		ans.lmax[1] = ansl.lmax[1], ans.lmax[0] = ansl.lmax[0];
		if(ansl.sum == ansl.len) ans.lmax[1] += ansr.lmax[1];
		if(ansl.sum == 0)        ans.lmax[0] += ansr.lmax[0];
		
		ans.rmax[1] = ansr.rmax[1], ans.rmax[0] = ansr.rmax[0];
		if(ansr.sum == ansr.len) ans.rmax[1] += ansl.rmax[1];
		if(ansr.sum == 0)	 ans.rmax[0] += ansl.rmax[0];
		
		ans.max[1] = max(ansl.max[1], ansr.max[1]);
		ans.max[1] = max(ans.max[1], ansl.rmax[1] + ansr.lmax[1]);
		ans.max[0] = max(ansl.max[0], ansr.max[0]);
		ans.max[0] = max(ans.max[0], ansl.rmax[0] + ansr.lmax[0]);
		
		return ans;
	}
} 

int main()
{
	n = read(), m = read();
	for(int i = 1; i <= n; ++i) a[i] = read();
	build(1, 1, n);
	for(int i = 1, opt, l, r; i <= m; ++i){
		opt = read(), l = read() + 1, r = read() + 1;
		if(opt == 0){ change01(1, 1, n, l, r, 0); }
		if(opt == 1){ change01(1, 1, n, l, r, 1); }
		if(opt == 2){ changef(1, 1, n, l, r); }
		if(opt == 3){ printf("%d\n", get_sum(1, 1, n, l, r));	}
		if(opt == 4){ printf("%d\n", get_max(1, 1, n, l, r).max[1]); }
	} 
	return 0;
}
相关文章
相关标签/搜索