浅谈树分治: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. 浅谈 Fork/Join

    fork/join的java7新添加的功能,能够把它理解成一个并发框架. 我们通过fork/join能将一个可分解的大任务.分解成多个子任务同步运行.运行完成后,在将各子任务的结果进行合并,得到终于的 ...

  2. EventListener中的handleEvent

    在研究代码时发现类似这样一段代码: function TEST() {} TEST.prototype = { init:function() { window.addEventListener('m ...

  3. 看完这篇再不会 View 的动画框架,我跪搓衣板

    引言 众所周知,一款没有动画的 app,就像没有灵魂的肉体,给用户的体验性很差.现在的 android 在动画效果方面早已空前的发展,1.View 动画框架 2.属性动画框架 3.Drawable 动 ...

  4. 用汇编的角度剖析c++的virtual

    多态是c++的关键技术,背后的机制就是有一个虚函数表,那么这个虚函数表是如何存在的,又是如何工作的呢? 当然不用的编译器会有不同的实现机制,本文只剖析vs2015的实现. 单串继承 首先看一段简单的代 ...

  5. 10个经典Java面试题

    1.Java的HashMap是怎样工作的? HashMap是一个针对数据结构的键值.每一个键都会有对应的值.关键是识别这种值. HashMap 基于 hashing 原理,我们通过 put ()和 g ...

  6. CountDownTimer

    package com.daoge.widget; import java.text.DecimalFormat; import android.os.CountDownTimer; import a ...

  7. 【BZOJ3291】Alice与能源计划 二分图最大匹配

    [BZOJ3291]Alice与能源计划 Description 在梦境中,Alice来到了火星.不知为何,转眼间Alice被任命为火星能源部长,并立刻面临着一个严峻的考验. 为了方便,我们可以将火星 ...

  8. 【题解】Painting Fence

    [题解]Painting Fence 分治模板.贪心加分治.直接\(O(n^2logn)\)分治过去.考虑一块联通的柱形是子问题的,是递归的,贪心分治就可.记得对\(r-l+1\)取\(min\). ...

  9. cocos2d-x中对象的位置,旋转,缩放

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/cuit/article/details/26729633 分为两种: 缓动.IntervalActi ...

  10. quick-cocos2d-x 系列之——环境搭建(Mac版)

    quick-cocos2d-x简单介绍 何为quick-cocos2d-x? ?   简单一句话:quick-cocos2d-x是採用lua语言,通过tolua++工具对cocos2d-x进一步封装, ...