[ZPG TEST 114] 括号匹配【树分治 点分治 括号序列】
- 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] 括号匹配【树分治 点分治 括号序列】的更多相关文章
- 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 ...
- CF308C-Sereja and Brackets-(线段树+括号匹配)
题意:给出一段括号,多次询问某个区间内能匹配多少括号. 题解:线段树,结构体三个属性,多余的左括号l,多余的右括号r,能够匹配的括号数val. 当前结点的val=左儿子的val+右儿子的val+min ...
- Sereja and Brackets(括号匹配)
Description Sereja has a bracket sequence s1, s2, ..., sn, or, in other words, a string s of length ...
- POJ1741——Tree(树的点分治)
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-11-17 1 ...
- 括号匹配 区间DP (经典)
描述给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来 ...
- HDU4812 D Tree(树的点分治)
题目大概说给一棵有点权的树,输出字典序最小的点对,使这两点间路径上点权的乘积模1000003的结果为k. 树的点分治搞了.因为是点权过根的两条路径的LCA会被重复统计,而注意到1000003是质数,所 ...
- YTU 3003: 括号匹配(栈和队列)
3003: 括号匹配(栈和队列) 时间限制: 1 Sec 内存限制: 128 MB 提交: 2 解决: 2 [提交][状态][讨论版] 题目描述 假设一个表达式中只允许包含三种括号:圆括号&quo ...
- C++,利用链式栈实现括号匹配,界面友好,操作方便,运行流畅
#include<iostream> #include<string> using namespace std; struct Node { char ch; Node* ne ...
- [原]NYOJ 括号匹配系列2,5
本文出自:http://blog.csdn.net/svitter 括号匹配一:http://acm.nyist.net/JudgeOnline/problem.php?pid=2 括号匹配二:htt ...
随机推荐
- 高精度乘法(FFT)
学会了FFT之后感觉自己征服了世界! 当然是幻觉... 不过FFT还是很有用的,在优化大规模的动规问题的时候有极大效果. 一般比较凶残的计数动规题都需要FFT(n<=1e9). 下面是高精度乘法 ...
- javascript中获取class
js中没有获取class的办法,找了一些封装好的方法,这里整理一下 (1)先进行封装 //封装getClass function getClass(tagName,className) //获得标签名 ...
- Codeforces Round #376 (Div. 2) A. Night at the Museum —— 循环轴
题目链接: http://codeforces.com/contest/731/problem/A A. Night at the Museum time limit per test 1 secon ...
- Java(二)——开发环境搭建 安装JDK和配置环境变量
1.安装JDK 下载地址 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载 ...
- 对Webview跨源攻击的理解
首先是addJavaScriptInterface漏洞: 有时候访问手机百度贴吧网页版本,网页上会有个按钮提示用手机应用打开.这种交互通常都是使用JS来实现,而WebView已经提供了这样的方法,具体 ...
- POJ 2970 The lazy programmer(贪心+单调优先队列)
A new web-design studio, called SMART (Simply Masters of ART), employs two people. The first one is ...
- <十三>UML核心视图静态视图之业务用例图
一:uml的核心视图 --->如果说UML是一门语言,上一章学习的参与者等元素是uml的基本词汇,那么视图就是语法.uml通过视图将基元素组织在一起,形成有意义的句子. --->uml可视 ...
- 《Objective-C高级编程》の内存管理の学习笔记
此日志用于记录下学习过程中碰到的问题 转载请注明出处: http://www.cnblogs.com/xdxer/p/4069650.html <Objective-C高级编程> 人民邮电 ...
- 用Merge存储引擎中间件实现MySQL分表
觉得一个用Merge存储引擎中间件来实现MySQL分表的方法不错. 可以看下这个博客写的很清楚--> http://www.cnblogs.com/xbq8080/p/6628034.html ...
- 爬虫库之BeautifulSoup学习(一)
Beautiful Soup的简介 简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据. 官方解释如下: Beautiful Soup提供一些简单的.pytho ...