前言:
emmm,学了点分治,第一眼看到这个题的时候,这不就是个点分治吗...然后看了除了点分治的其他解法..emmm好简单啊.然后我把点分治复习了一遍,顺便敲了下其他的解法~
Solution 1:
思维:假如是边权为1的点,相互之间为偶数距离的点对个数的话,必定满足一个条件,就是黑白染色之后颜色相同.我们不妨设根节点为1,进行一次dfs即可.
复杂度:.
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+50;
vector<int>g[N];
ll f[2];
void dfs(int u,int fa,int dep)
{
f[dep]++;
for(int v:g[u])
{
if(v==fa) continue;
dfs(v,u,dep^1);
}
}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<n;i++)
{
int v,u;
scanf("%d%d",&v,&u);
g[v].push_back(u);
g[u].push_back(v);
}dfs(1,1,1);
printf("%lld\n",f[0]*(f[0]-1)/2+f[1]*(f[1]-1)/2);
return 0;
}Solution 2:
点分治:直接进行点分治,统计下子树的奇偶性状况,然后计数即可.
复杂度:.
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+50,M=2;
vector<int>g[N];
int root,sz[N],f[N],sum;
ll num[M],ans;
bool vis[N];//标记这个点是否被用过.
void f_root(int u,int fa)
{
sz[u]=1,f[u]=0;
for(int v:g[u])
{
if(v==fa||vis[v]) continue;
f_root(v,u);sz[u]+=sz[v];
f[u]=max(f[u],sz[v]);
}f[u]=max(f[u],sum-sz[u]);
if(f[u]<f[root]) root=u;
}
void cnt_node(int u,int fa,int val)
{
num[val]++;
for(int v:g[u])
{
if(vis[v]||v==fa) continue;
cnt_node(v,u,val^1);
}
}
void cnt_ans(int u,int fa,int val)
{
ans+=num[val];
for(int v:g[u])
{
if(vis[v]||v==fa) continue;
cnt_ans(v,u,val^1);
}
}
void cal(int u,int val)
{
for(int v:g[u])
{
if(vis[v]) continue;
cnt_ans(v,u,val^1);
cnt_node(v,u,val^1);
}
}
void solve(int u)
{
num[0]++;cal(u,0);
vis[u]=true;
memset(num,0,sizeof num);
for(int v:g[u])
{
if(vis[v]) continue;
root=0,sum=sz[v];
f_root(v,u);
solve(v);
}
}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<n;i++)
{
int v,u;
scanf("%d%d",&v,&u);
g[v].push_back(u);
g[u].push_back(v);
}f[0]=n,sum=n,root=0;
f_root(1,0);solve(root);
printf("%lld\n",ans);
return 0;
}
京公网安备 11010502036488号