【JZOJ3234】阴阳
时间:2019-07-11
本文章向大家介绍【JZOJ3234】阴阳,主要包括【JZOJ3234】阴阳使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目大意
给出一棵\(n\)个点的树,每条边的权值是1或0,一条路径合法的条件是:路径上存在一个休息点(不能是起点也不能是终点),使得起点到该点路径上0和1的个数相等,该点到终点的路径上0和1的个数也相等。求合法路径条数。
分析
求满足条件的树上路径条数显然是点分治。
考虑分治中心\(x\),对于两条路径\(x->u\)和\(x->v\),路径\(u->v\)合法有三种情况:
- 休息点在\(x->u\)上
- 休息点在\(x->v\)上
- 休息点在\(u\)
将0视作-1,将1视作1,一条路径0和1的个数相等等价于路径权值和为0,那么我们只需要预处理每个点\(u\),路径\(x->u\)是否有休息点,然后用两个桶统计一下答案就行了。为了便于计算答案,我们一棵一棵子树做,就不用容斥了。
Code
#include <cstdio>
#include <cstring>
typedef long long ll;
const int N = 300007;
int max(int a, int b) { return a > b ? a : b; }
ll ans;
int n;
int sum, p, tot, st[N], to[N << 1], nx[N << 1], len[N << 1], siz[N], maxsiz[N], del[N];
void add(int u, int v, int w) { to[++tot] = v, nx[tot] = st[u], len[tot] = (w == 1 ? -1 : 1), st[u] = tot; }
void getp(int u, int from)
{
siz[u] = 1, maxsiz[u] = 0;
for (int i = st[u]; i; i = nx[i]) if (to[i] != from && !del[to[i]]) getp(to[i], u), siz[u] += siz[to[i]], maxsiz[u] = max(maxsiz[u], siz[to[i]]);
maxsiz[u] = max(maxsiz[u], sum - siz[u]);
if (maxsiz[u] < maxsiz[p]) p = u;
}
int cnt, arr[N], dis[N], ok[N], buc[N * 4], b[N * 4], b0[N * 4];
void getdis(int u, int from)
{
if (b0[dis[u] + N]) ok[u] = 1;
else ok[u] = 0;
arr[++cnt] = u, b0[dis[u] + N]++;
for (int i = st[u]; i; i = nx[i]) if (to[i] != from && !del[to[i]]) dis[to[i]] = dis[u] + len[i], getdis(to[i], u);
b0[dis[u] + N]--;
}
void solve(int u)
{
del[u] = 1, dis[u] = 0;
for (int i = st[u]; i; i = nx[i])
if (!del[to[i]])
{
ll ret = 0;
cnt = 0, dis[to[i]] = len[i], getdis(to[i], u);
for (int j = 1; j <= cnt; j++)
{
if (ok[arr[j]])
{
ret += b[N - dis[arr[j]]] + buc[N - dis[arr[j]]];
if (!dis[arr[j]]) ret++;
}
else
{
ret += buc[N - dis[arr[j]]];
if (!dis[arr[j]]) ret += b[N];
}
}
for (int j = 1; j <= cnt; j++)
{
if (ok[arr[j]]) buc[dis[arr[j]] + N]++;
else b[dis[arr[j]] + N]++;
}
ans += ret;
}
dis[u] = 0, getdis(u, 0);
for (int i = 1; i <= cnt; i++) b[dis[arr[i]] + N] = 0, buc[dis[arr[i]] + N] = 0, ok[arr[i]] = 0;
for (int i = st[u]; i; i = nx[i]) if (!del[to[i]]) sum = siz[to[i]], p = 0, getp(to[i], 0), solve(p);
}
int main()
{
scanf("%d", &n);
for (int i = 1, u, v, w; i < n; i++) scanf("%d%d%d", &u, &v, &w), add(u, v, w), add(v, u, w);
sum = n, maxsiz[0] = N, getp(1, 0), solve(p);
printf("%lld\n", ans);
return 0;
}
原文地址:https://www.cnblogs.com/zjlcnblogs/p/11173293.html
- Kafka源码系列之使用要点总结及重要错误解决
- Kafka源码系列之实现自己的kafka监控
- Kafka源码系列之副本同步机制及isr列表更新
- Kafka源码系列之topic创建分区分配及leader选举
- Kafka源码系列之如何删除topic
- Kafka源码系列之kafka如何实现高性能读写的
- Kafka源码系列之分组消费的再平衡策略
- Kafka源码系列之Consumer高级API性能分析
- Kafka源码系列之源码解析SimpleConsumer的消费过程
- Spark调优系列之序列化方式调优
- Spark源码系列之foreach和foreachPartition的区别
- kafka源码系列之mysql数据增量同步到kafka
- Hbase源码系列之BufferedMutator的Demo和源码解析
- Kafka源码系列之0.10版本的Producer源码解析及性能点讲解
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux下完全删除用户的两种方法
- flutter实现轮播图效果
- Ubuntu 16.04设置PostgreSQL开机启动的方法
- 使用userdel命令删除Linux用户的教程详解
- Linux系统交换空间介绍
- 小内存服务器上宝塔默认安装的MySQL如何优化配置
- (译)SDL编程入门(15)旋转和翻转
- linux解决ping通但端口不通的问题
- (译)SDL编程入门(13)透明度混合
- 基于centos宝塔面版的安装Discuz! Q方法
- 如何在Linux中的特定时间运行命令
- composer 安装过程中,提示404错误
- Linux初始化系统盘后重新挂载数据盘方法
- 在页面部分没有发现字符集声明,请增加该声明
- Linux使用Sudo委派权限