洛谷题目传送门

闲话

偶然翻到一道没有题解的淀粉质,想证明一下自己是真的弱

然而ZSYC(字符串组合)早就切了

然后证明成功了,WA到怀疑人生,只好借着ZSY的代码拍,拍了几万组就出来了。。。

思路

是人都能想到的:路径统计,点分治跑不了了。

然而这个统计有些麻烦。。。

首先别看错题,是中间的一个点到两个端点的两条路径都要满足黑白相等。(因为蒟蒻就看错了)

显然,我们每次要统计经过重心的路径,但是这个中点不一定会在重心。于是,必须要更一般化地统计了。

容易想到的是差分。记\(d_x\)为\(x\)到重心路径上黑白个数的差,可以改一下边权变成\(1\)和\(-1\),更好实现。

这时候,我们已经可以做到统计黑白个数相等的路径了,一对差分值为\(d\)和\(-d\)的路径就可以产生贡献。

但是,题目要两条子路径都黑白相等啊!再想想,假设有两个点\(x,y,d_x=-d_y\),那么是不是只有在\(x\)的祖先中存在\(z\)且\(d_z=-d_y\),或者在\(y\)的祖先中存在\(z\)且\(d_x=-d_z\),路径\(x-y\)才能贡献答案?

这也就是说,我们选择的中点\(z\)的\(d\)值,需要和\(d_x\)或\(d_y\)相等才行。

于是,我们根据每个点是否有祖先的\(d\)等于它的\(d\),分成两类。显然,没有的点只能和有的点算贡献,而有的点可以和两种点都算贡献。开两个桶区别统计一下就好了。

具体实现的话,蒟蒻直接依次枚举重心的子树,先统计一个子树的答案,再把子树的每个点丢进桶里。这样就不用容斥去除不合法情况了。但是要特判一个端点在重心上的路径的贡献。

如何快速判断当前点的属于哪一类?开一个数组\(b\)统计祖先中每个\(d\)值出现的次数就可以了(\(d\)可能是负数,要把所有下标加\(n\))。注意回溯的时候要减掉。

注意答案要开long long,注意清空数组。

代码算是很短的了。

#include<cstdio>
#include<cstring>
#define RG register
#define R RG int
#define G c=getchar()
const int N=1e5+1,M=N<<1;
int n,rt,mx,mn,he[N],ne[M],to[M],c[M],s[N],m[N],b[M],f[M],g[M];
bool vis[N];
long long ans;
inline void min(R&x,R y){if(x>y)x=y;}
inline void max(R&x,R y){if(x<y)x=y;}
inline int in(){
RG char G;
while(c<'-')G;
R x=c&15;G;
while(c>'-')x=x*10+(c&15),G;
return x;
}
void dfs(R x){//求重心
vis[x]=1;s[x]=1;m[x]=0;
for(R y,i=he[x];i;i=ne[i])
if(!vis[y=to[i]])
dfs(y),s[x]+=s[y],max(m[x],s[y]);
max(m[x],n-s[x]);
if(m[rt]>m[x])rt=x;
vis[x]=0;
}
void upd(R x,R d){//统计答案,f没有g有
min(mn,d);max(mx,d);
ans+=g[M-d];//分类贡献
if(b[d])ans+=f[M-d];
if(d==N)ans+=b[d]>1;//特判
vis[x]=1;++b[d];
for(R i=he[x];i;i=ne[i])
if(!vis[to[i]])upd(to[i],d+c[i]);
vis[x]=0;--b[d];//回溯清零
}
void mdf(R x,R d){//修改桶
++(b[d]?g[d]:f[d]);
vis[x]=1;++b[d];
for(R i=he[x];i;i=ne[i])
if(!vis[to[i]])mdf(to[i],d+c[i]);
vis[x]=0;--b[d];
}
void div(R x){//分治
rt=0;dfs(x);x=rt;
vis[x]=1;b[mn=mx=N]=1;//此处注意初始化
R t=n,y,i;
for(i=he[x];i;i=ne[i])
if(!vis[y=to[i]])
upd(y,N+c[i]),mdf(y,N+c[i]);
memset(f+mn,0,(mx-mn+1)<<2);//注意清空
memset(g+mn,0,(mx-mn+1)<<2);
for(i=he[x];i;i=ne[i])
if(!vis[y=to[i]])
n=s[x]>s[y]?s[y]:t-s[x],div(y);
}
int main(){
m[0]=1e9;n=in();
for(R a,b,p=0,i=1;i<n;++i){
a=in();b=in();
ne[++p]=he[a];to[he[a]=p]=b;
ne[++p]=he[b];to[he[b]=p]=a;
c[p]=c[p-1]=in()?1:-1;//处理边权
}
div(1);
printf("%lld\n",ans);
return 0;
}

洛谷P3085 [USACO13OPEN]阴和阳Yin and Yang(点分治,树上差分)的更多相关文章

  1. 洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)

    洛谷题目传送门 思路分析 最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了) 考虑如何优化算法.如果没有1操作,肯定每个树都长一样.有了1操作,就来仔细分析一下对不 ...

  2. 【洛谷 P2633】 Count on a tree(主席树,树上差分)

    题目链接 思维难度0 实现难度7 建出主席树后用两点的状态减去lca和lca父亲的状态,然后在新树上跑第\(k\)小 #include <cstdio> #include <cstr ...

  3. 洛谷P3345 [ZJOI2015]幻想乡战略游戏(动态点分治,树的重心,二分查找,Tarjan-LCA,树上差分)

    洛谷题目传送门 动态点分治小白,光是因为思路不清晰就耗费了不知道多少时间去gang这题,所以还是来理理思路吧. 一个树\(T\)里面\(\sum\limits_{v\in T} D_vdist(u,v ...

  4. 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)

    题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...

  5. Bzoj1202/洛谷P2294 [HNOI2005]狡猾的商人(带权并查集/差分约束系统)

    题面 Bzoj 洛谷 题解 考虑带权并查集,设\(f[i]\)表示\(i\)的父亲(\(\forall f[i]<i\)),\(sum[i]\)表示\(\sum\limits_{j=fa[i]} ...

  6. 洛谷 P5502 - [JSOI2015]最大公约数(区间 gcd 的性质+分治)

    洛谷题面传送门 学校模拟赛的某道题让我联想到了这道题-- 先讲一下我的野鸡做法. 首先考虑分治,对于左右端点都在 \([L,R]\) 中的区间我们将其分成三类:完全包含于 \([L,mid]\) 的区 ...

  7. 洛谷 P3084 [USACO13OPEN]照片Photo 解题报告

    [USACO13OPEN]照片Photo 题目描述 农夫约翰决定给站在一条线上的\(N(1 \le N \le 200,000)\)头奶牛制作一张全家福照片,\(N\)头奶牛编号\(1\)到\(N\) ...

  8. 洛谷 P2209 [USACO13OPEN]燃油经济性Fuel Economy

    P2209 [USACO13OPEN]燃油经济性Fuel Economy 题目描述 Farmer John has decided to take a cross-country vacation. ...

  9. 洛谷3084 [USACO13OPEN]照片Photo

    原题链接 神仙\(DP\)啊... 题解请移步隔壁大佬的博客\(QAQ\) #include<cstdio> using namespace std; const int N = 2e5 ...

随机推荐

  1. Apache cxf暴露接口以及客户端调用之WebService初步理解

    在我们真实的项目中,经常会调用别人提供给我们的接口,或者在自己的团队中, restful风格的前后端分离也经常会提供一个后端接口暴露出去供app,或者.net/C/C++程序员去调用,此时就需要使用到 ...

  2. 记一次在.NET成长之路上的下午茶

    在2017年2月25日我和李海国有幸与阳铭.朱永光两位大哥喝了一次下午茶.熟悉ABP框架的朋友呢知道阳铭远在上海,所以个人很是珍惜这次机会.朱永光大哥是微软MVP,之前是启路科技的CTO,目前在微软. ...

  3. Linux ip forward

    Linux 默认带有 ip forward 功能,只不过因为各种原因,默认的配置把该功能关闭了.本文通过 demo 来演示 Linux 的 ip forward 功能,具体场景为:开启 Linux 的 ...

  4. Shell学习笔记二

    一.调试脚本 调试功能是每一种编程语言都应该实现的重要特性之一,当出现一些始料未及的情况时,用它来生成脚本运行信息.调试信息可以帮你弄清楚是什么原因使得程序发生崩溃或行为异常.每位系统程序员都应该了解 ...

  5. MariaDB第三章(select)

    基本查询 --查询基本使用(条件,排序,聚合函数,分组,分页) --创建学生表 create table students ( id int unsigned not null auto_increm ...

  6. ULMFiT 阅读笔记

    ULMFiT 阅读笔记 概述 这篇文章从文本分类模型入手,主要提出了两点:一是预训练语言模型在大中小规模的数据集中都能提升分类效果,在小规模数据集中效果尤为显著.二是提出了多种预训练的调参方法,包括D ...

  7. Linux内核分析第三章读书笔记

    第三章 进程管理 3.1 进程 进程就是处于执行期的程序 进程就是正在执行的程序代码的实时结果 线程:在进程中活动的对象.每个线程都拥有一个独立的程序计数器.进程栈和一组进程寄存器. 内核调度的对象是 ...

  8. 《Linux内核分析与实现》 第五周 读书笔记

    第3章 进程管理 20135307张嘉琪 3.1 进程 进程就是处于执行期的程序(目标码存放在某种存储介质上),但进程并不仅仅局限于一段可执行程序代码.通常进程还要包含其他资源,像打开的文件,挂起的信 ...

  9. iOS推送证书生成pem文件(详细步骤)

    1.pem文件概述 pem文件是服务器向苹果服务器做推送时候需要的文件,主要是给php向苹果服务器验证时使用,下面介绍一下pem文件的生成. 2.生成pem文件步骤 1.打开钥匙串,选择需要生成的推送 ...

  10. TextView设置文字包含中英文时自动换行问题的终极解决方案

    情景,正常TextView中设置文本内容中包含中英文时会造成自动换行的问题,影响界面显示效果,如图: 网上很多解决途径,甚至有多三方框架处理,但是效果并不能达到,最终是要如下代码完美解决,效果图如下: ...