CF1149C Tree Generator™

CF1149C Tree Generator™

不能暴力建树,考虑从括号序入手。

联想树上莫队的点括号序列,一段区间去掉匹配括号剩下的括号对应的点即为路径上的点,有特殊情况。

则这里边括号序列,发现特殊情况都给你省掉了,那么一条路径对应一个区间去掉匹配括号。

那么有,树上直径长度为任意区间去掉匹配括号后的长度的最大值。

考虑如何代数去除匹配括号,树上莫队是判奇偶,这里可以设左端点为 11,右端点为 1-1

问题变为找到相邻的两段,使后一段的数字和减前一段的数字和的差最大,这个差就是答案。

因为后一段的数字和,对应一条向下的链,前一段的数字和对应一条向上的链,减去是因为向上的链的非匹配括号数计算是反过来的,即 111、-1 交换。

区间最大差,考虑维护区间前后缀最大差以及整个区间的最大差。

需要维护区间前后缀最大最小子段和辅助计算。

一棵线段树即可,时间复杂度 O(nlogn)\mathcal O(n\log n)

#include<bits/stdc++.h>

using namespace std;

//#define int long long
typedef long long ll;
#define ha putchar(' ')
#define he putchar('\n')

inline int read()
{
	int o = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-')
			f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
		o = o * 10 + c - '0', c = getchar();
	return o * f;
}

inline void write(int o)
{
	if(o < 0)
	{
		putchar('-');
		o = -o;
	}
	if(o > 9)
		write(o / 10);
	putchar(o % 10 + '0');
}

const int _ = 2e5 + 10;

int n, q;

int tr[_ << 2], su[_ << 2], lm[_ << 2], rm[_ << 2], ln[_ << 2], rn[_ << 2], ld[_ << 2], rd[_ << 2], zd[_ << 2];

// m 大 n 小 d 右减左

char s[_];

void pushup(int o)
{
	su[o] = su[o << 1] + su[o << 1 | 1];
	lm[o] = max(lm[o << 1], su[o << 1] + lm[o << 1 | 1]);
	rm[o] = max(rm[o << 1 | 1], su[o << 1 | 1] + rm[o << 1]);
	ln[o] = min(ln[o << 1], su[o << 1] + ln[o << 1 | 1]);
	rn[o] = min(rn[o << 1 | 1], su[o << 1 | 1] + rn[o << 1]);
	
	ld[o] = max(ld[o << 1], max(ld[o << 1 | 1] - su[o << 1], zd[o << 1] + lm[o << 1 | 1]));
	rd[o] = max(rd[o << 1 | 1], max(su[o << 1 | 1] + rd[o << 1], zd[o << 1 | 1] - rn[o << 1]));
	
	zd[o] = max(zd[o << 1] + su[o << 1 | 1], zd[o << 1 | 1] - su[o << 1]);
	tr[o] = max(max(ld[o << 1 | 1] - rn[o << 1], rd[o << 1] + lm[o << 1 | 1]), max(tr[o << 1], tr[o << 1 | 1]));
}

void build(int o, int l, int r)
{
	if(l == r)
	{
		int v = s[l] == '(' ? 1 : -1;
		su[o] = v;
		lm[o] = rm[o] = max(v, 0);
		ln[o] = rn[o] = min(v, 0);
		ld[o] = rd[o] = zd[o] = tr[o] = 1;
		return;
	}
	int mid = (l + r) >> 1;
	build(o << 1, l, mid), build(o << 1 | 1, mid + 1, r);
	pushup(o);
}

void upd(int o, int l, int r, int p, int v)
{
	if(l == r)
	{
		su[o] = v;
		lm[o] = rm[o] = max(v, 0);
		ln[o] = rn[o] = min(v, 0);
		ld[o] = rd[o] = zd[o] = tr[o] = 1;
		return;
	}
	int mid = (l + r) >> 1;
	if(p <= mid) upd(o << 1, l, mid, p, v);
	else upd(o << 1 | 1, mid + 1, r, p, v);
	pushup(o);
}

signed main()
{
	n = read(), q = read();
	scanf("%s", s + 1);
	n = (n - 1) << 1;
	build(1, 1, n);
	write(tr[1]), he;
	int a, b;
	while(q--)
	{
		a = read(), b = read();
		if(s[a] != s[b])
		{
			swap(s[a], s[b]);
			upd(1, 1, n, a, s[a] == '(' ? 1 : -1);
			upd(1, 1, n, b, s[b] == '(' ? 1 : -1);
		}
		write(tr[1]), he;
	}
	return 0;
}
posted @ 2022-08-01 20:12  蒟蒻orz  阅读(2)  评论(0编辑  收藏  举报  来源