Newcoder 111 A.托米的简单表示法(树形)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/V5ZSQ/article/details/83055747

Description

一天,他正在为解析算术表达式的课程准备课件。 在课程的第一部分,他只想专注于解析括号。 他为他的学生发明了一个有趣的正确括号序列的几何表示,如下图所示:

在这里插入图片描述

几何表示的定义:

1.对于一个括号序列 A A ,我们定义 g ( A ) g(A) A A 的几何表示形式,则 ( ) " “()" 的表示是一个 1 1 1*1 的方块,高度为 1 1 ;

2.对于一个括号序列 A A ( A ) " “(A)" 的表示是由一个比 g ( A ) g(A) 2 2 个单位高 1 1 个单位的矩形包围 g ( A ) g(A) ,它的高度为 A + 1 A+1 ;

3.对于两个括号序列 A A B B A + B A+B 的几何表示形式为把 g ( B ) g(B) 放置在 g ( A ) g(A) 右边的一个单位,且高度为 A A B B 的高度的较大值。其中+指的是字符串的连接符。​

在完成课件后,托米老师开始玩他做好的图片。 他将图像的有限区域交替地涂成黑色和白色,使最外面的区域全部涂成黑色。 对于上面的例子,这个着色如下所示:

img

现在给你一个合法的括号序列。 请计算颜色为黑色的区域的面积。

Input

输入的第一行包含一个整数 T T ,表示指定测试用例的数量。

每个测试用例前面都有一个空白行。

每个测试用例由一个合法括号序列 s s 组成。 每行只包含字符 ( '(' ) ')'

( 1 T 10 , s 4 1 0 5 ) (1\le T\le 10,|s|\le 4\cdot 10^5)

Output

对于每个测试用例,输出一行包含一个整数,表示相应几何表示的黑色部分的面积。

Sample Input

2

((()))

(())(()(()))

Sample Output

10
20

Solution

将该合法括号序列看作一个森林的 d f s dfs 序,左括号表示从当前节点走向一个新的儿子节点,右括号则表示从当前节点走向父亲节点,建树后考虑 u u 节点所代表左括号和与之配对的右括号形成的区域中黑色块的面积,记为 d p ( u ) dp(u) ,为了维护面积,多维护两个值 h ( u ) , w ( u ) h(u),w(u) 分别表示只考虑以 u u 为根的子树中所有节点构成区域的高度和宽度,那么显然有转移
h ( u ) = max v s o n ( u ) { h ( v ) } + 1 , w ( u ) = s o n ( u ) + 1 + v s o n ( u ) w ( v ) h(u)=\max\limits_{v\in son(u)}\{h(v)\}+1,w(u)=|son(u)|+1+\sum\limits_{v\in son(u)}w(v)
进而有
d p ( u ) = h ( u ) w ( u ) v s o n ( u ) d p ( v ) dp(u)=h(u)\cdot w(u)-\sum\limits_{v\in son(u)}dp(v)
累加该森林每棵树根节点的 d p dp 值即为答案,时间复杂度 O ( n ) O(n)

Code

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=400005;
int T,fa[maxn],h[maxn],w[maxn];
char c[maxn]; 
vector<int>g[maxn];
ll dp[maxn];
void dfs(int u)
{
	if(g[u].size()==0)
	{
		h[u]=w[u]=dp[u]=1;
		return ;
	}
	h[u]=dp[u]=0,w[u]=g[u].size()+1;
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i];
		dfs(v);
		h[u]=max(h[u],h[v]+1);
		w[u]+=w[v];
		dp[u]-=dp[v];
	}
	dp[u]+=(ll)h[u]*w[u];
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%s",c);
		int n=strlen(c);
		for(int i=0;i<n;i++)g[i].clear(),fa[i]=-1;
		int u=0;
		for(int i=1;i<n;i++)
			if(c[i]=='(')g[u].push_back(i),fa[i]=u,u=i;
			else u=fa[u];
		ll ans=0;
		for(int i=0;i<n;i++)
			if(c[i]=='('&&fa[i]==-1)
			{
				dfs(i);
				ans+=dp[i];
			}
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/V5ZSQ/article/details/83055747
111