codeforces 1149c

给出了()的字符串,这里的()字符串可以看成是dfs序列,再求lca时的那张表。
所以这一个序列就可以看成是在dfs序上面,求树的直径。
取某一段[l,r],可以知道lca一定在[l,r]之间。
我们就用公式 diameter=hight[l]+height[r]-2* height[lca(l,r)]来维护两个点的之间的距离。
把(看成1,)看成-1,可以发现height[i]=sufix[i],即前缀和。
所以我们建立一颗线段树,维护hight[l]+height[r]-2* height[lca(l,r)]这个式子即可。
针对这个式子,我们一共有三种方式可以统计diameter,当前区间的diameter=max(左子树diameter,右子树diameter,跨接两个区间的diameter )
关在在于怎么去求跨界两个区间的。我们可以维护 height[l]-2*height[lca]来得到。即左子树的 往右边方向的lca去连接右边,右子树 往左边方向走的lca去链接左边,满足l<=lca<=r,即lca在我们取的两点之间。(注意合并时还有细节,比如我们并没有直接维护前缀和,而是根节点置为深度1,不断加深度来完成,方便后面更新节点,也可以直接维护深度进行区间修改,不过要复杂一点)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 2e5 + 10;
struct node {
	int depth, lmx, rmx, mn, mx,as;
	node operator +(const node a)const {
		node b;
		b.depth = depth + a.depth;
		b.mx = max(mx, a.mx + depth);
		b.mn = min(mn, a.mn + depth);
		b.lmx = max(lmx, a.lmx - depth); b.lmx = max(b.lmx, mx - 2 * a.mn - 2 * depth);
		b.rmx = max(rmx, a.rmx - depth); b.rmx = max(b.rmx, a.mx - 2 * mn + depth);
		b.as = max(as, a.as);
		b.as = max(b.as, max(lmx + a.mx + depth, a.rmx + mx - depth));
		return b;
	}
}tree[N << 2];
void update(int l, int r, int root, int pos,int val)
{
	if (l == r)
	{
		tree[root].depth = val;
		tree[root].mn = tree[root].mx = val;
		tree[root].lmx = tree[root].rmx = -val;
		tree[root].as = 0;
		return;
	}
	int mid = (l + r) >> 1;
	if (pos <= mid)update(lson, pos, val);
	else update(rson, pos, val);
	tree[root] = tree[lrt] + tree[rrt];
}
int n, q;
int a, b;
char s[N];
int main()
{
	n = read(); q = read();
	n = 2 * n - 2;
	cin >> s + 1;
	upd(i, 1, n)
	{
		update(1, n, 1, i, s[i] == '(' ? 1 : -1);
	}
	printf("%d\n", tree[1].as);
	while (q--)
	{
		a = read(), b = read();
		update(1, n, 1, a, s[b] == '(' ? 1 : -1);
		update(1, n, 1, b, s[a] == '(' ? 1 : -1);
		swap(s[a], s[b]);
		printf("%d\n", tree[1].as);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值