浅谈树分治:https://www.cnblogs.com/AKMer/p/10014803.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3127

这题很合我的胃口,要我统计树上的“太极”路径。

假设没有要求中间某个点到两端黑白也是相等的,那么我们直接用\(f[i]\)记录黑白两种边的差值为\(i\)的路径有多少条就行了。但是要求路径上需要存在中间某个点到两个端点的黑白边也是相同的。那么我们就用\(f[i][0]\)记录差值为\(i\),不存在这种点的路径条数,\(f[i][1]\)记录存在这种点的路径条数。然后根据根到当前点的路径上有无这种点,分别用\(f[-num][0]+f[-num][1]\)和\(f[-num][1]\)更新即可,\(num\)表示根到当前点的路径上黑白边的差值。如果判断路径上是否有这种点呢?记一个全局数组\(sum\),\(sum[i]\)表示在当前递归的栈里,从根到这个点路径上黑白边差值为\(i\)的点有多少个。如果\(sum[num]\)不为零,那么从根到当前点的路径上必然会有一个这样的点。

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

点分治版代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define fr first
#define sc second const int maxn=1e5+5; ll ans;
bool vis[maxn];
int n,tot,mx,rt,N;
int sum[maxn<<1],f[maxn<<1][2],siz[maxn];
int now[maxn],pre[maxn*2],son[maxn*2],val[maxn*2]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} void add(int a,int b,int c) {
pre[++tot]=now[a];
now[a]=tot,son[tot]=b,val[tot]=c;
} struct rubbish {
int top;
pii sta[maxn];
bool bo[maxn<<1][2]; void clear() {
while(top) {
int num1=sta[top].fr,num2=sta[top].sc;
bo[num1][num2]=0,f[num1][num2]=0,top--;
}
} void ins(int a,int b) {
if(bo[a][b])return;
bo[a][b]=1;
sta[++top]=make_pair(a,b);
}
}R; void find_son(int fa,int u) {
int res=0;siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa)find_son(u,v),siz[u]+=siz[v],res=max(res,siz[v]);
res=max(res,N-siz[u]);
if(res<mx)mx=res,rt=u;
} void query(int fa,int u,int num) {
if(sum[num+maxn]||num==0)ans+=f[-num+maxn][0]+f[-num+maxn][1];
else ans+=f[-num+maxn][1];
sum[num+maxn]++;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa)query(u,v,num+val[p]);
sum[num+maxn]--;
} void solve(int fa,int u,int num) {
f[num+maxn][sum[num+maxn]!=0]++;
R.ins(num+maxn,sum[num+maxn]!=0);
sum[num+maxn]++,siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa)solve(u,v,num+val[p]),siz[u]+=siz[v];
sum[num+maxn]--;
} void work(int u,int size) {
N=size,mx=rt=n+1,find_son(0,u),u=rt,vis[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]) {
query(u,v,val[p]);
solve(u,v,val[p]);
}
ans+=f[maxn][1];R.clear();
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v])work(v,siz[v]);
} int main() {
n=read();
for(int i=1;i<n;i++) {
int a=read(),b=read(),c=(read()<<1)-1;
add(a,b,c),add(b,a,c);
}work(1,n);printf("%lld\n",ans);
return 0;
}

边分治版代码如下:

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define fr first
#define sc second const int maxn=2e5+5; ll ans;
bool vis[maxn];
int n,tot,mx,id,N;
int siz[maxn],f[maxn<<1][2],sum[maxn<<1];
int now[maxn],pre[maxn*2],son[maxn*2],val[maxn*2]; vector<pii>to[maxn];
vector<pii>::iterator it; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} void add(int a,int b,int c) {
pre[++tot]=now[a];
now[a]=tot,son[tot]=b,val[tot]=c;
} void find_son(int fa,int u) {
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(v!=fa)to[u].push_back(make_pair(v,val[p])),find_son(u,v);
} void rebuild() {
tot=1;memset(now,0,sizeof(now));
for(int i=1;i<=n;i++) {
int size=to[i].size();
if(size<=2) {
for(it=to[i].begin();it!=to[i].end();it++) {
pii tmp=*it;
add(i,tmp.fr,tmp.sc),add(tmp.fr,i,tmp.sc);
}
}
else {
pii u1=make_pair(++n,0),u2;
if(size==3)u2=to[i].front();
else u2=make_pair(++n,0);
add(i,u1.fr,u1.sc),add(u1.fr,i,u1.sc);
add(i,u2.fr,u2.sc),add(u2.fr,i,u2.sc);
if(size==3) {
for(int j=1;j<3;j++)
to[n].push_back(to[i].back()),to[i].pop_back();
}
else {
int p=0;
for(it=to[i].begin();it!=to[i].end();it++) {
if(!p)to[n-1].push_back(*it);
else to[n].push_back(*it);p^=1;
}
}
}
}
} struct rubbish {
int top;
pii sta[maxn];
bool bo[maxn<<1][2]; void clear() {
while(top) {
int num1=sta[top].fr,num2=sta[top].sc;
bo[num1][num2]=0,f[num1][num2]=0,top--;
}
} void ins(int a,int b) {
if(bo[a][b])return;
bo[a][b]=1,sta[++top]=make_pair(a,b);
}
}R; void find_edge(int fa,int u) {
siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[p>>1]&&v!=fa) {
find_edge(u,v),siz[u]+=siz[v];
if(abs(N-2*siz[v])<mx)
mx=abs(N-2*siz[v]),id=p>>1;
}
} void solve(int fa,int u,int num,bool bo) {
if(bo) {
f[num+maxn][(sum[num+maxn]!=0)]++;
R.ins(num+maxn,sum[num+maxn]!=0),sum[num+maxn]++;
}siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[p>>1]&&v!=fa)solve(u,v,num+val[p],val[p]!=0),siz[u]+=siz[v];
if(bo)sum[num+maxn]--;
} void query(int fa,int u,int num,bool bo) {
if(bo) {
if(!sum[num+maxn])ans+=f[-num+maxn][1];
else {
ans+=f[-num+maxn][0]+f[-num+maxn][1];
if(val[id<<1]==0&&num==0)ans--;//这种情况就是,在u2所在的联通块里找到了一条满足条件的路径,但是会在这里被f[-num+maxn][0],也就是0号点到u1的路径匹配上算一次,到时候去处理u2所在的联通块会被重复计算,所以就减掉了。
}
sum[num+maxn]++;
}siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[p>>1]&&v!=fa)query(u,v,num+val[p],val[p]!=0),siz[u]+=siz[v];
if(bo)sum[num+maxn]--;
} void work(int u,int size) {
if(size<2)return;
N=size,mx=id=n+1,find_edge(0,u),vis[id]=1;
int u1=son[id<<1],u2=son[id<<1|1];
solve(0,u1,0,1),query(0,u2,val[id<<1],(val[id<<1]!=0));
R.clear(),work(u1,siz[u1]),work(u2,siz[u2]);
} int main() {
n=read();
for(int i=1;i<n;i++) {
int a=read(),b=read(),c=(read()<<1)-1;
add(a,b,c),add(b,a,c);
}find_son(0,1),rebuild();
work(1,n),printf("%lld\n",ans);
return 0;
}

BZOJ3127:[USACO2013OPEN]Yin and Yang的更多相关文章

  1. bzoj3127/3697 [Usaco2013 Open]Yin and Yang

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3127 http://www.lydsy.com/JudgeOnline/problem.ph ...

  2. 洛谷P3085 [USACO13OPEN]阴和阳Yin and Yang(点分治,树上差分)

    洛谷题目传送门 闲话 偶然翻到一道没有题解的淀粉质,想证明一下自己是真的弱 然而ZSYC(字符串组合)早就切了 然后证明成功了,WA到怀疑人生,只好借着ZSY的代码拍,拍了几万组就出来了... 思路 ...

  3. 【BZOJ】【3697】采药人的路径&【3127】【USACO2013 Open】Yin and Yang

    点分治 Orz hzwer 倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误…… 1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移. ...

  4. Yin and Yang Stones(思路题)

    Problem Description: A mysterious circular arrangement of black stones and white stones has appeared ...

  5. BZOJ 3127 [Usaco2013 Open]Yin and Yang(树点分治)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3127 [题目大意] 给出一棵01边权树,求存在多少条路径,使得路径上0和1的数量相同, ...

  6. Usaco2012-2013 金组 题解 (暂缺Hill walk以及Figue eight)

    https://files.cnblogs.com/files/Winniechen/usaco2012-2013.pdf 做的不是很好,还请见谅! 如果有什么疑问,可以QQ上找我. QQ号:1967 ...

  7. 转:Mysql在大型网站的应用架构演变

    原文来自于:http://www.cnblogs.com/Creator/p/3776110.html 原创文章,转载请注明: 转载自http://www.cnblogs.com/Creator/本文 ...

  8. 更换JDK版本时的问题:Error: could not open `C:\Java\jre7\lib\amd64\jvm.cfg'

    1.先把oracle自带的weblogic给卸载了,然后打开eclipse,发现报错了:Error: could not open `C:\Java\jre7\lib\amd64\jvm.cfg' J ...

  9. Ansible13:Playbook循环语句

    目录 循环语句 简介 loop关键字说明 在循环语句中注册变量 旧循环语句 1. with_items 2. with_nested 3. with_dict 4. with_fileglob 5. ...

随机推荐

  1. Python,Pycharm,Anaconda等的关系与安装过程~为初学者跳过各种坑

    1.致欢迎词 我将详讲讲述在学Python初期的各种手忙脚乱的问题的解决,通过这些步骤的操作,让你的注意力集中在Python的语法上以及后面利用Python所解决的项目问题上.而我自己作为小白,很不幸 ...

  2. 小东和三个朋友一起在楼上抛小球,他们站在楼房的不同层,假设小东站的楼层距离地面N米,球从他手里自由落下,每次落地后反跳回上次下落高度的一半,并以此类推知道全部落到地面不跳,求4个小球一共经过了多少米?(数字都为整数) 给定四个整数A,B,C,D,请返回所求结果。

    include #include<vector> using namespace std; class Balls { public: int calcDistance(int A, in ...

  3. android 关于ScrollView 的博客做记录学习

    1.Android ScrollView向上滑动控件顶部悬浮效果实现 2.[android]仿知乎ScrollView滚动改变标题栏透明度 3.github开源Android组件资源整理(五)Scro ...

  4. eclipse集成tomcat改动字符集參数

    问题: 在eclipse 4.4(Luna)中集成tomcat时,直接改动原tomcat文件夹中的配置文件,不起作用. 有时.我们会修改字符集參数为utf-8,以解决中文乱码问题,修改之后依旧乱码-- ...

  5. Centos7重新安装yum

    Centos7重新安装yum rpm -qa|grep yum 然后用下面的命令删除出现的xxx包: rpm -e --nodeps xxx 下载 python-urlgrabber-3.10-8.e ...

  6. thinkphp5, 结合pgsql使用时, 要先运行这段sql代码

    按照tp5的官方文档的说法, 必须这么做: 先执行一段sql代码 CREATE OR REPLACE FUNCTION pgsql_type(a_type varchar) RETURNS varch ...

  7. 用keytool创建Keystore和Trustsotre文件只需五步

    用keytool创建Keystore和Trustsotre文件 JSSE使用Truststore和Keystore文件来提供客户端和服务器之间的安全数据传输.keytool是一个工具可以用来创建包含公 ...

  8. ABAP 调用webservice 错误

    错误:1.soamanager 配置端口错误: 调整端口后报错: java端回复: 嗯 有问题了我待会儿看看应该是数据有问题 

  9. PAT 乙级 1085. PAT单位排行 (25) 【结构体排序】

    题目链接 https://www.patest.cn/contests/pat-b-practise/1085 思路 结构体排序 要注意几个点 它的加权总分 是 取其整数部分 也就是 要 向下取整 然 ...

  10. html5/CSS3鼠标滑过图片特效插件

    在线演示 本地下载