[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 ...
随机推荐
- Windows下配置PHPUnit(pear已弃用,使用phpunit.phar)
一.配置PHPUnit 首先到PHPUnit官网(点此进入)下载相应的版本.php 5.5及以下版本请使用PHPUnit 4.8.得到 .phar 文件,并把名字改为 phpunit.phar . 把 ...
- Codeforces Round #198 (Div. 2) E. Iahub and Permutations —— 容斥原理
题目链接:http://codeforces.com/contest/340/problem/E E. Iahub and Permutations time limit per test 1 sec ...
- 人生苦短之Python枚举类型enum
枚举类型enum是比较重要的一个数据类型,它是一种数据类型而不是数据结构,我们通常将一组常用的常数声明成枚举类型方便后续的使用.当一个变量有几种可能的取值的时候,我们将它定义为枚举类型.在Python ...
- 「ZJOI2007」「LuoguP1169」棋盘制作(并查集
题目描述 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8×88 \times 88×8大小的黑白相间的方阵,对应八八六十四卦 ...
- python optparse模块的简单用法
# coding = utf-8 from optparse import OptionParser from optparse import OptionGroup usage = 'Usage: ...
- Java使用Jacob转换Word为HTML
从今天开始,我也要养成记录开发中遇到的问题和解决方法的好习惯! 最近开发一个Android项目,需要用到查看Word和Pdf文档的功能,由于Android没有直接显示Word和PDF文档的组件,只有一 ...
- hihoCoser(#1149 : 回文字符序列)
时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定字符串,求它的回文子序列个数.回文子序列反转字符顺序后仍然与原序列相同.例如字符串aba中,回文子序列为"a& ...
- sip协议呼叫流程详解
1.SIP业务基本知识 1.1 业务介绍会话初始协议(Session Initiation Protocol)是一种信令协议,用于初始.管理和终止网络中的语音和视频会话,具体地说就是用来生成.修改和终 ...
- 3.sql中的向上递归和向下递归
1.向下递归 select * from table_name where 条件 connect by prior bmbm(本级关联条件)=sjbmbm(上级关联条件) start with bmb ...
- Bayesian 网络分类算法
1:贝叶斯网络的定义和性质 一个贝叶斯网络定义包括一个有向无环图(DAG)和一个条件概率表集合.DAG中每一个节点表示一个随机变量,可以是可直接观测变量或隐藏变量,而有向边表示随机变量间的条件依赖:条 ...