阴阳

题面



分析

个人认为是极好的题,很容易写

如果你学点分治是无奈背板的,那就做做这道题,加深你对点分治的理解

一般的,处理树上大规模统计问题,我们分治的关键是找一棵子树的重心

找到分治中心,即新一轮的根节点,然后处理子树节点经过根节点时的答案,接着对子树继续分治下去

那么我们看这题,让黑白的各自变为 \(1\) 或 \(-1\)

合法的路径是这样的:能找到一个分割点使路径两端各自的和分别为 \(0\)

那么我们思考在统计经过根节点的答案时,只有不同子树的两路径合并时或一棵子树中某节点到根距离为 \(0\) 且其路径上有分割点才可能产生答案

也就是说,我们要找的路径和必须为 \(0\) 且有分割点

找路径和为 \(0\) 很简单,记录子树节点到根的距离 \(dis\)(可能为负,所以让他加上 \(n\) 避免出错),两路径合并时,设其两端为 \(x,y\),\(dis[x]+dis[y] = 0\) 是必要条件

重点就是如何判断两路径是否有分割点,是的话我们就可以统计答案

那么我们回到 \(dis[x]+dis[y] = 0\) 这句话

\(dis[y]=-dis[x]\),若 \(dis[y]\) 他到根节点中 值是非第一次出现的,那么可以直接贡献答案

我们只需要记下这类点的个数就好了,即开桶以值为下标记个数,我们称其为二类桶

???那一类桶呢?

既然二类桶是非第一次出现,那一类桶就记第一次出现的个数

我们可以用 \(flag[x]=1\) 表示 \(dis[x]\) 已经出现过

因为是遍历子树是深搜的顺序,所以我们再开个桶标记在他到根节点路径中 \(dis\) 出现的次数,这样就可以很好的判断 \(flag\) 是否需要标记为 \(1\)

那么考虑当前节点如何计算答案

  • 若他的 \(dis\) 到根节点是第一次出现,那么他可以直接加上二类桶。注意 \(dis\) 为 \(0\) 的话他又可以加一类桶,因为此时的根可以为路径的分割点
  • 若他的 \(dis\) 到根节点不是第一次出现,那么他可以加上一、二类桶,因为他先前的 \(dis\) 到他的距离为 \(0\),即先前的 \(dis\) 可做分割点。当然,此时他 \(dis\) 若为 \(0\) 同理说明他到根也是合法路径,所以答案加 \(1\)。记得标记当前点的 \(flag\) 为 \(1\)

    每次统计完一个子树,就要再遍历一遍这个子树更新一类、二类桶的信息

换重心时我们不能直接把数组清 \(0\),为了保证复杂度,我们统计完所有子树的答案后再遍历一遍所有子树,将一类、二类桶的信息退回,\(flag\) 和 \(dis\) 清 \(0\)

完结撒花

\(Code\)

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL; const int N = 1e5 + 5;
int n , buc[N << 1] , buc1[N << 1][3] , flag[N] , dis[N] , h[N] , size , siz[N] , son[N] , rt , use[N] , tot;
LL ans; struct edge{
int to , nxt , w;
}e[2 * N]; inline void add(int x , int y , int z)
{
e[++tot].nxt = h[x];
e[tot].to = y;
e[tot].w = z;
h[x] = tot;
} inline void getrt(int x , int fa)
{
son[x] = 0 , siz[x] = 1;
for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa || use[v]) continue;
getrt(v , x);
siz[x] += siz[v];
son[x] = max(son[x] , siz[v]);
}
son[x] = max(son[x] , size - siz[x]);
rt = son[x] < son[rt] ? x : rt;
} inline void getdis(int x , int fa)
{
for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa || use[v]) continue;
dis[v] = dis[x] + e[i].w;
getdis(v , x);
}
} inline void fill(int x , int fa)
{
++buc1[dis[x] + n][flag[x]];
for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa || use[v]) continue;
fill(v , x);
}
} inline void clear(int x , int fa)
{
--buc1[dis[x] + n][flag[x]];
for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa || use[v]) continue;
clear(v , x);
}
dis[x] = flag[x] = 0;
} inline LL dfs(int x , int fa)
{
LL res = 0;
if (buc[dis[x] + n]) flag[x] = 1 , res += buc1[-dis[x] + n][0] + buc1[-dis[x] + n][1] + (!dis[x] ? 1 : 0);
else{
if (!dis[x]) res += buc1[-dis[x] + n][0];
res += buc1[-dis[x] + n][1];
}
++buc[dis[x] + n]; for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa || use[v]) continue;
res += dfs(v , x);
}
--buc[dis[x] + n];
return res;
} inline LL calc(int x)
{
getdis(x , 0);
LL res = 0;
for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (use[v]) continue;
res += dfs(v , x);
fill(v , x);
}
for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (use[v]) continue;
clear(v , x);
}
return res;
} inline void divide(int x)
{
use[x] = 1 , ans += calc(x);
for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (use[v]) continue;
size = siz[v] , rt = 0;
getrt(v , x) , divide(rt);
}
} int main()
{
scanf("%d" , &n);
int u , v , w;
for(register int i = 1; i < n; i++)
{
scanf("%d%d%d" , &u , &v , &w);
w = w ? 1 : -1;
add(u , v , w) , add(v , u , w);
}
son[0] = 2e9 , size = n;
getrt(1 , 0) , divide(rt);
printf("%lld" , ans);
}

JZOJ 3234. 阴阳的更多相关文章

  1. 伏羲八卦、文王六十四卦、老子阴阳太极、西方哲学辩证与"解耦和复用”思想的异曲同工之妙

    伏羲八卦.文王六十四卦.老子阴阳太极.西方哲学辩证与"解耦和复用”思想的异曲同工之妙     问题:任何程序语言在遇到复杂逻辑时,代码维护难度就会加大,如何处理该问题? 答案:重构,模块化. ...

  2. bzoj 3234: [Ahoi2013]立方体

    题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3234 题意:求长方体交的表面积. 思路:flood-fill const int ...

  3. 【HDOJ】3234 Exclusive-OR

    并查集.对于对元素赋值操作,更改为I p n v.令val[n]=0(任何数与0异或仍为原值).考虑fa[x] = fx, fa[y] = fy.如果使得fa[fx] = fy, 那么val[fx] ...

  4. scheme 阴阳谜题

    本篇分析continuation的一个著名例子"阴阳迷题",这是由David Madore先生提出的,原谜题如下: (let* ((yin ((lambda (foo) (disp ...

  5. 使用CSS达到阴阳八卦图等图形

    CSS还是比較强大的,能够实现中国古典的"阴阳八卦图"等形状. 正方形 #rectangle { width: 200px; height: 100px; backgrount-c ...

  6. (jzoj snow的追寻)线段树维护树的直径

    jzoj snow的追寻 DFS序上搞 合并暴力和,记录最长链和当前最远点,距离跑LCA # include <stdio.h> # include <stdlib.h> # ...

  7. [jzoj]3506.【NOIP2013模拟11.4A组】善良的精灵(fairy)(深度优先生成树)

    Link https://jzoj.net/senior/#main/show/3506 Description 从前有一个善良的精灵. 一天,一个年轻人B找到她并请他预言他的未来.这个精灵透过他的水 ...

  8. [jzoj]3468.【NOIP2013模拟联考7】OSU!(osu)

    Link https://jzoj.net/senior/#main/show/3468 Description osu 是一款群众喜闻乐见的休闲软件. 我们可以把osu的规则简化与改编成以下的样子: ...

  9. [jzoj]5478.【NOIP2017提高组正式赛】列队

    Link https://jzoj.net/senior/#main/show/5478 Description Sylvia 是一个热爱学习的女孩子.       前段时间,Sylvia 参加了学校 ...

  10. [jzoj]1115.【HNOI2008】GT考试

    Link https://jzoj.net/senior/#main/show/1115 Description 申准备报名参加GT考试,准考证号为n位数X1X2X3...Xn-1Xn(0<=X ...

随机推荐

  1. linux sublime-text ctrl+shift+b 快捷键失效问题解决

    解决办法 由于fcitx拦截了这个ctrl+shift+b 这个快捷键,所以取消即可 点击全局配置里面高级选项,然后找到ctrl+shift+b这个快捷键,点击后,按esc就可以将快捷键设置为空,不过 ...

  2. 干货 | 如何快速实现 BitSail Connector?

    简介 本文面向 BitSail 的 Connector 开发人员,通过开发者的角度全面的阐述开发一个完整 Connector 的全流程,快速上手 Connector 开发. 目录结构 首先开发者需要通 ...

  3. 为什么推荐Kestrel作为网络开发框架

    为什么推荐Kestrel 网络框架千千万万,在dotnet平台,我们可以直接手撸Socket,也可以基于dotnetty来开发,或者选择某些第三方类似于dotnetty的网络库,为何我要推荐Kestr ...

  4. BUU_RE学习记录

    一.easyre 1.010打开,直接搜flag,得到flag 二.reverse1 1.先查壳,得知是64位无壳,直接用IDA打开 2.shiftF12查找字符串,发现关键语句 3.查看相应代码,F ...

  5. go语言的grpc环境安装

    本文直接用安装包的方式安装. 源码编译安装参考:https://www.cnblogs.com/abc36725612/p/14288333.html 环境 golang的docker image d ...

  6. MYSQL的回忆录(适合有基础的小伙伴看,没基础的看着估计够呛)

    SQL分类 MYSQL的数据类型 Text 类型 数据类型 描述 CHAR(size) 保存固定长度的字符串(可包含字母.数字以及特殊字符).在括号中指定字符串的长度.最多 255 个字符. VARC ...

  7. 痞子衡嵌入式:Farewell, 我的写博故事2016-2019

    -- 题图:苏州天平山枫叶 现在是 2022 年末,痞子衡又要起笔博文年终总结了,看着 2020 年之前的博文总结缺失,始终觉得缺憾,所以写下此篇 2016 - 2019 总结合辑.2016 年之前, ...

  8. 1_使用swiper数组对象循环图片遇到的问题

    今天在练习微信小程序的swiper组件时,想用列表循环出图片,发现图片一直没出来,控制台也没有报错,后来仔细一看,原来是语法格式写错了. 以下是我列表循环踩过的坑: 一:微信小程序的列表循环和vue的 ...

  9. 《Effective C++》实现 章节

    Item26:尽可能延后变量定义式的出现时间 Item27:尽量少做转型动作 关于这一点,专门开了一个新的总结: http://blog.csdn.net/m0_37316917/article/de ...

  10. 就dispatch_source_t写的计时器

    直接上干货,我这里用的是Xcode12.4,macOS:11.2.3 OC版本:               swift版本: