1. 1.      括号匹配

 

有一棵树,每个节点上都有一个括号(左括号或者右括号)。有多少个有序点对(u, v)从u到v的路径上的节点构成的字符串是一个合法的括号匹配?(我们称这样的点对是合法的)

输入格式

第一行是一个整数n,表示节点个数

第二行是一个字符串,由(和)组成,第i个字符表示第i个节点的括号。

接下来n-1行,每行两个整数u, v 表示u与v之间有一条边。

输出格式

输出一个整数,合法的点对数量。

输入样例

输出样例

4

()()

1 2

2 3

3 4

4

数据范围和约定

30%的数据:n <= 2000

100%的数据:n <= 100000

困扰了我多年(其实是多个月),终于于今日解决了!(我才不会说克罗地亚国赛最后一题是原题呢= =)如果没做过树分治的话还是先做一下poj1741感受一下叭。

先把随题配送的题解贴出来:

“这道题是很常规的树分治算法。分治之后考虑经过根的所有链,将链上的所有能匹配的括号合并,那么只有其中一边由若干左括号和另外一边的若干右括号的情况能构成合法的括号匹配。统计括号数即可。”

写的非常简洁,然而最初根本看不懂。事实上是这样子的,首先考虑当前子树,一条合法的括号序列链可以经过该子树的根节点,也可以不经过,对于后者可以递归求解,重点是看前者。

一条链经过这个根节点,那么这条链一定是长成这个样子的:

/ \

/     \

/         \

/             \

姑且把根旁边的两条支叫做左支与右支(注意原树并不一定是二叉树),那么这个括号序列一定是由左支的一些已经匹配好的括号序列,与右支的一些已经匹配好的括号序列,与左支还未匹配的 '(' 与右支未匹配的 ')' 。当然也有可能是由左支的一些已经匹配好的括号序列,与右支的一些已经匹配好的括号序列,与右支还未匹配的 '(' 与左支未匹配的 ')' 。这里不妨考虑前者。现在关键就是让那些分在两支的未匹配的括号得以匹配。具体的话还是看代码,最关键的是get_data()函数。还需要小注意一下78行的注释内容。

#include <cstdio>
#include <cstring>
#include <algorithm> const int maxn = 100005, LEFT = 0, RIGHT = 1; int n, head[maxn], to[maxn << 1], next[maxn << 1], lb, a[maxn], mp[128];
int t1, t2, siz[maxn], cnt[2][maxn], avail_len[2][maxn], idx[2], sum[2][maxn];
long long ans;
char ch, book[maxn]; inline void ist(int aa, int ss) {
to[lb] = ss;
next[lb] = head[aa];
head[aa] = lb;
++lb;
}
void get_siz(int r, int p) {
siz[r] = 1;
for (int j = head[r]; j != -1; j = next[j]) {
if (!book[to[j]] && to[j] != p) {
get_siz(to[j], r);
siz[r] += siz[to[j]];
}
}
}
void fnd_zx(int r, int tot_node, int p, int & real_r, int & mn) {
int mx = 0;
for (int j = head[r]; j != -1; j = next[j]) {
if (!book[to[j]] && to[j] != p) {
fnd_zx(to[j], tot_node, r, real_r, mn);
mx = std::max(mx, siz[to[j]]);
}
}
mx = std::max(mx, tot_node - siz[r]);
if (mn > mx) {
mn = mx;
real_r = r;
}
}
void get_data(int r, int p, int dir, int avail, int s) {
// r是当前子树的根节点,p是其父亲,dir是你想要找的可供与另一支匹配的括号类型,
// avail表示目前可供匹配的个数,s有点玄 ,只有当s为零的时候,这个括号序列才是
// 可以用来与另一支匹配的,用语言不好表达,简单模拟一下程序的45~61行就懂了
if (a[r] == dir) {
if (s) {
--s;
}
else {
++avail;
}
}
else {
++s;
}
if (!s) {
if (!cnt[dir][avail]) {
avail_len[dir][idx[dir]++] = avail;
}
++cnt[dir][avail];
}
for (int j = head[r]; j != -1; j = next[j]) {
if (!book[to[j]] && to[j] != p) {
get_data(to[j], r, dir, avail, s);
}
}
}
void slove(int fake_r) {
int real_r = -666, mn = 2147483647, tem;
get_siz(fake_r, 0);
fnd_zx(fake_r, siz[fake_r], 0, real_r, mn);
book[real_r] = 1;
for (int j = head[real_r]; j != -1; j = next[j]) {
if (!book[to[j]]) {
slove(to[j]);
}
}
int mx_avail = 1; // mx_avail must be initialized to 1! 0 is NOT OK!
for (int j = head[real_r]; j != -1; j = next[j]) {
if (!book[to[j]]) {
if (a[real_r] == LEFT) {
get_data(to[j], real_r, LEFT, 1, 0);
get_data(to[j], real_r, RIGHT, 0, 0);
}
else {
get_data(to[j], real_r, RIGHT, 1, 0);
get_data(to[j], real_r, LEFT, 0, 0);
}
for (int dir = 0; dir < 2; ++dir) {
for (int k = 0; k < idx[dir]; ++k) {
tem = avail_len[dir][k];
mx_avail = std::max(mx_avail, tem);
ans -= (long long)cnt[dir][tem] * cnt[dir ^ 1][tem];
sum[dir][tem] += cnt[dir][tem];
cnt[dir][tem] = 0;
}
idx[dir] = 0;
}
}
} ++sum[a[real_r]][1];
for (int i = 0; i <= mx_avail; ++i) {
ans += (long long)sum[0][i] * sum[1][i];
sum[0][i] = 0;
sum[1][i] = 0;
} book[real_r] = 0;
} int main(void) {
freopen("bracket.in", "r", stdin);
freopen("bracket.out", "w", stdout);
memset(head, -1, sizeof head);
memset(next, -1, sizeof next);
mp['('] = LEFT;
mp[')'] = RIGHT;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
while ((ch = getchar()) < '(');
a[i] = mp[(int)ch];
}
for (int i = 1; i < n; ++i) {
scanf("%d%d", &t1, &t2);
ist(t1, t2);
ist(t2, t1);
} slove(1);
printf("%I64d\n", ans);
return 0;
}

  

[ZPG TEST 114] 括号匹配【树分治 点分治 括号序列】的更多相关文章

  1. C. Serval and Parenthesis Sequence 【括号匹配】 Codeforces Round #551 (Div. 2)

    冲鸭,去刷题:http://codeforces.com/contest/1153/problem/C C. Serval and Parenthesis Sequence time limit pe ...

  2. CF308C-Sereja and Brackets-(线段树+括号匹配)

    题意:给出一段括号,多次询问某个区间内能匹配多少括号. 题解:线段树,结构体三个属性,多余的左括号l,多余的右括号r,能够匹配的括号数val. 当前结点的val=左儿子的val+右儿子的val+min ...

  3. Sereja and Brackets(括号匹配)

    Description Sereja has a bracket sequence s1, s2, ..., sn, or, in other words, a string s of length  ...

  4. POJ1741——Tree(树的点分治)

    1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-11-17 1 ...

  5. 括号匹配 区间DP (经典)

    描述给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来 ...

  6. HDU4812 D Tree(树的点分治)

    题目大概说给一棵有点权的树,输出字典序最小的点对,使这两点间路径上点权的乘积模1000003的结果为k. 树的点分治搞了.因为是点权过根的两条路径的LCA会被重复统计,而注意到1000003是质数,所 ...

  7. YTU 3003: 括号匹配(栈和队列)

    3003: 括号匹配(栈和队列) 时间限制: 1 Sec  内存限制: 128 MB 提交: 2  解决: 2 [提交][状态][讨论版] 题目描述 假设一个表达式中只允许包含三种括号:圆括号&quo ...

  8. C++,利用链式栈实现括号匹配,界面友好,操作方便,运行流畅

    #include<iostream> #include<string> using namespace std; struct Node { char ch; Node* ne ...

  9. [原]NYOJ 括号匹配系列2,5

    本文出自:http://blog.csdn.net/svitter 括号匹配一:http://acm.nyist.net/JudgeOnline/problem.php?pid=2 括号匹配二:htt ...

随机推荐

  1. WSDL文档深入分析

    借助jdk的wsimort.exe工具生成客户端代码 格式:wsimport -keep url   //url为wsdl文件的路径 直接生成客户端代码会抛异常, 无法生成客户端代码, 解决办法: 将 ...

  2. LightOJ1213 Fantasy of a Summation —— 快速幂

    题目链接:https://vjudge.net/problem/LightOJ-1213 1213 - Fantasy of a Summation    PDF (English) Statisti ...

  3. 写给精明Java开发者的测试技巧

    我们都会为我们的代码编写测试,不是吗?毫无疑问,我知道这个问题的答案可能会从 “当然,但你知道怎样才能避免写测试吗?” 到 “必须的!我爱测试”都有.接下来我会给你几个小建议,它们可以让你编写测试变得 ...

  4. 测试jdbc连接下,mysql和mycat的吞吐性能

    最近一个项目需要数据库有较大的吞吐量,因为项目要求的访问量和数据量较大,决定采用一个数据库中间件来对数据库进行管理.经过一番查询,决定使用阿里的一个开源项目-mycat.因为mycat基于mysql, ...

  5. EnumDescription

    using System; using System.Reflection; using System.Collections; using System.Collections.Generic; n ...

  6. Tensorflow和Caffe 简介

    TensorFlow TensorFlow 是相对高阶的机器学习库,用户可以方便地用它设计神经网络结构,而不必为了追求高效率的实现亲自写 C++或 CUDA 代码.它和 Theano 一样都支持自动求 ...

  7. FFmpeg常用命令 (二)

    使用网络上的各种转码软件,简直崩溃了!比如,它竟然强行把你要编辑的视频的前面,现在可以使用ffmpeg. ffmpeg做IT media的都知道,很强大,只不多对windows用户比较麻烦,可以使用L ...

  8. ABI(Application Binary Interface)

    拷贝自维基百科,参考百度百科 ==>调用栈结构与系统相关. 在计算机中,应用二进制接口(英语:application binary interface,缩写为 ABI)描述了应用程序(或者其他类 ...

  9. tomcat 的一些知识

    常见web服务器 1. WebLogic 支持J2EE规范2. WebSphere 支持J2EE3. Tomcat 支持JSP,servlet规范 需要配置JDK才能运行 tomcat JAVA_HO ...

  10. Websocket 学习

    一.含义 WebSocket 是一种在单个TCP连接上进行全双工通讯的协议.   WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据.在WebSocket ...