您的位置:首页 > 其它

【BZOJ1468】Tree [点分治]

2017-02-25 20:42 281 查看

Tree

Time Limit: 10 Sec  Memory Limit: 64 MB
[Submit][Status][Discuss]

Description

  给你一棵TREE,以及这棵树上边的距离,问有多少对点它们两者间的距离小于等于K。

Input

  第一行一个n,接下来n-1行边描述管道,按照题目中写的输入,接下来是一个k。

Output

  仅包括一个整数,表示有多少对点之间的距离小于等于k。

Sample Input

  7
  1 6 13
  6 3 9
  3 5 7
  4 1 3
  2 4 20
  4 7 2
  10

Sample Output

  5

HINT

  n<=40000

Solution

  树上路径统计问题,运用点分。
  每次处理与重心相关的路径,发现如果直接处理两点之间比较困难,我们想到了将所有点加入一个数组,用指针判断加起来<=K的个数,这样的话不一定全是简单路径,但是我们只要减去每个子树中这样操作的条数就一定只剩下简单路径了。
  点分大概的步骤:
  1.找出重心;
  2.计算经过该重心的路径相关需要求的;
  3.去掉重心对于每棵子树继续做以上过程。

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;

const int ONE=80001;

int n,K;
int x,y,z;
int next[ONE],first[ONE],go[ONE],w[ONE],tot;
int center_vis[ONE];
int Max,dist[ONE],num;
int d[ONE];
int center,Ans;

int get()
{
int res,Q=1;    char c;
while( (c=getchar())<48 || c>57)
if(c=='-')Q=-1;
if(Q) res=c-48;
while((c=getchar())>=48 && c<=57)
res=res*10+c-48;
return res*Q;
}

int Add(int u,int v,int z)
{
next[++tot]=first[u];   first[u]=tot;   go[tot]=v;  w[tot]=z;
next[++tot]=first[v];   first[v]=tot;   go[tot]=u;  w[tot]=z;
}

namespace PointF
{
struct power
{
int maxx,size;
}S[ONE];

void Getsize(int u,int father)
{
S[u].size=1;
S[u].maxx=0;
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || center_vis[v]) continue;
Getsize(v,u);
S[u].size+=S[v].size;
S[u].maxx=max(S[u].maxx,S[v].size);
}
}

void Getcenter(int u,int father,int total)
{
S[u].maxx=max(S[u].maxx,total-S[u].size);
if(Max>S[u].maxx)
{
Max=S[u].maxx;
center=u;
}

for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || center_vis[v]) continue;
Getcenter(v,u,total);
}
}

void Getdist(int u,int father,int value)
{
dist[++num]=value;
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || center_vis[v]) continue;
Getdist(v,u,value+w[e]);
}
}

int Calc(int u,int value)
{
int res=0;
num=0;

Getdist(u,0,value);
sort(dist+1,dist+num+1);

int l=1,r=num;

while(l<r)
{
while(dist[l]+dist[r]>K && l<r) r--;
res+=r-l;
l++;
}
return res;
}

void Dfs(int u)
{
Max=n;
Getsize(u,0);

center=u;
Getcenter(u,0,S[u].size);
center_vis[center]=true;

Ans+=Calc(center,0);
for(int e=first[center];e;e=next[e])
{
int v=go[e];
if(center_vis[v]) continue;
Ans-=Calc(v,w[e]);
Dfs(v);
}
}
}

int main()
{
n=get();
for(int i=1;i<n;i++)
{
x=get();    y=get();    z=get();
Add(x,y,z);
}

K=get();
PointF::Dfs(1);

printf("%d",Ans);
}
View Code

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: