[COCI2010-2011#6] STEP

Description

sol:

这道题类似区间最大子段和。我们维护 lm, rm, ms,分别表示左右最长子串,全局最长子串。pushup的时候,计算ms时,应该为左右儿子内部的ms与跨越左右区间的ms的最大值。

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 2e5 + 100;

struct Node {
	int l, r;
	int lm, rm, ms;
} tr[N << 2];

int n, q;
bool a[N];

void pushup(int u) {
	Node & ls = tr[u << 1], rs = tr[u << 1 | 1];
	tr[u].lm = ls.lm;
	if( ls.lm == ls.r - ls.l + 1 && a[ls.r] ^ a[rs.l])
		tr[u].lm = max(tr[u].lm, ls.lm + rs.lm);
	tr[u].rm = rs.rm;
	if( rs.rm == rs.r - rs.l + 1 && a[rs.l] ^ a[ls.r])
	    tr[u].rm = max(tr[u].rm, rs.rm + ls.rm);
	tr[u].ms = max(ls.ms, rs.ms);
	if( a[ls.r] ^ a[rs.l]) {
		tr[u].ms = max(tr[u].ms, ls.rm + rs.lm);
	}
}

void change(int u, int k) {
	if( tr[u].l == tr[u].r) {
		a[tr[u].l] ^= 1;
		return;
	}
	int mid = tr[u].l + tr[u].r >> 1;
	if(k <= mid)	change(u << 1, k);
	else change(u << 1 | 1, k);
	pushup(u);
} 

void build(int u, int l, int r) {
	tr[u].l = l, tr[u].r = r;
	tr[u].ms = tr[u].lm = tr[u].rm = 1;
	if(l == r)	return;
	int mid = l + r >> 1;
	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); 
}

int main()
{
	scanf("%d%d", &n, &q);
	build(1, 1, n);
	while(q --) {
		int k;
		scanf("%d", &k);
		change(1, k);
		printf("%d
", tr[1].ms);
	}
	return 0;
}
/*
3 1
2

*/
原文地址:https://www.cnblogs.com/wyy0804/p/13769280.html