您的位置:首页 > 其它

【poj1987】Distance Statistics

2016-07-19 15:32 323 查看
link to problem

//听说1741也是一样的题目啊(⊙o⊙)

【题目大意】

给出一棵树,求树上有多少个点对 ( i , j ) 满足dis( i , j )<=k (1 <= k <= 1,000,000,000)。

【题解】点分治入门题

本题关键在于k太大了,无法水过QAQ

于是我们开始思考,在一棵根为rt(既然是点分治根节点显然就是树的重心了)的树内符合条件的点对( i , j ),可以分为以下两种情况:

( 1 ) 点 i,j 都在rt的某一棵子树中;

( 2 ) 点 i,j 分别在rt的两棵不同子树中;

显然对于情况(1)我们可以把它分解为情况(2)的方法来做。

于是对于一棵树,求出树内所有节点到根节点的距离,算出满足dis[i]+dis[j]<=k的点对(i,j)的数量。不过在这些点对中可能存在在同一棵子树里的情况,于是将它们扣除就得到为我们所要求的答案啦。

【呆马(⊙v⊙)】

#include <cstdio>
#include <algorithm>
#define maxn 100000
struct edge{ int to,s,nxt;}e[maxn];
int n,m,cnt,k,mx,rt,ans,tot,
fi[maxn],dis[maxn],d[maxn],size[maxn],f[maxn];
bool bo[maxn];
void add(int u,int v,int w)
{
e[++cnt].to=v;e[cnt].s=w;
e[cnt].nxt=fi[u];fi[u]=cnt;
}
void findrt(int x,int fa)
{
int mxx=0;size[x]=1;
for (int i=fi[x];i;i=e[i].nxt)
if (e[i].to!=fa && !bo[e[i].to])
{
findrt(e[i].to,x);
size[x]+=size[e[i].to];
mxx=std::max(mxx,size[e[i].to]);
}
mxx=std::max(mxx,tot-mxx);
if (mxx<mx) rt=x,mx=mxx;
}
void dfs(int x,int fa)
{
d[++d[0]]=dis[x];
for (int i=fi[x];i;i=e[i].nxt)
if (fa!=e[i].to && !bo[e[i].to])
{
dis[e[i].to]=dis[x]+e[i].s;
dfs(e[i].to,x);
}
}
int cal(int x)
{
d[0]=0;dfs(x,0);
std::sort(d+1,d+d[0]+1);
int ans=0;
for (int l=1,r=d[0];l<=r;)
if (d[l]+d[r]<=k) ans+=r-l,++l;
else --r;
return ans;
}
void dp(int x)
{
bo[x]=true;
dis[x]=0;ans+=cal(x);
for (int i=fi[x];i;i=e[i].nxt)
if (!bo[e[i].to])
{
dis[x]=e[i].s;
ans-=cal(e[i].to);
rt=0;mx=tot=size[e[i].to];
findrt(e[i].to,0);
dp(rt);
}
}
int main()
{
scanf("%d%d\n",&n,&k);
for (int i=1;i<n;++i)
{
int u,v,w;char ch;
scanf("%d %d %d\n",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
mx=tot=n;rt=0;findrt(1,0);
dp(rt);printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 点分治