您的位置:首页 > 其它

poj 1987 Distance Statistics 点分治

2016-07-19 17:09 423 查看
题目大意: 给你一棵树,问两个点对距离<=k的点对个数;

题目分析:点分治裸题。dfs处理出每个重心(分治下)到当前子树根节点的距离存在dis数组中,o(n)直接找出。

但要注意的是,对于dis所存的距离,只适用于两个不同的子树当中,所以要将位于同一个子树中的方案数减去。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cctype>
#include<cassert>
#include<climits>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define RepD(i,n) for(int i=n;i>=0;i--)
#define MEM(a) memset(a,0,sizeof(a))
#define MEMI(a) memset(a,127,sizeof(a))
#define MEMi(a) memset(a,128,sizeof(a))
#define INF (2139062143)
#define phiF (1000000006)
#define MAXN (1000000+10)
typedef long long LL;

struct info{
int to,next,val;
bool use;
}e[100005];
int x,y,z,n,m,tot,first[100005],son[50005],f[50005],size,root,a[50005],dis[50005],k,ans;

void add(int x,int y,int z){
e[tot].to=y;
e[tot].val=z;
e[tot].next=first[x];
first[x]=tot;tot++;
}

void findroot(int u,int fa){
son[u]=1;f[u]=0;
for (int p=first[u];p!=-1;p=e[p].next){
int v=e[p].to;
if (v==fa) continue;
if (e[p].use) continue;
findroot(v,u);
f[u]=max(f[u],son[v]);
son[u]+=son[v];
}
f[u]=max(f[u],size-son[u]);
if (f[u]<f[root]) root=u;
}

void dfs(int u,int fa){
son[u]=1;
a[++a[0]]=dis[u];
for (int p=first[u];p!=-1;p=e[p].next){
int v=e[p].to;
if (!e[p].use&&v!=fa){
dis[v]=dis[u]+e[p].val;
dfs(v,u);
son[u]+=son[v];
}
}

}

int count(int u,int val){
int tmp=a[0]=0;
dis[u]=val;
dfs(u,0);
sort(a+1,a+a[0]+1);
for (int l=1,r=a[0];l<r;){
if (a[l]+a[r]<=k){
tmp+=r-l;l++;
} else r--;
}
return tmp;

}

void work(int u){
ans+=count(u,0);
for (int p=first[u];p!=-1;p=e[p].next){
if (!e[p].use){
e[p^1].use=true;
ans-=count(e[p].to,e[p].val);
f[0]=size=son[e[p].to];root=0;
findroot(e[p].to,0);
work(root);

}
}

}
char ch;

int main(){
memset(first,-1,sizeof(first));
scanf("%d%d",&n,&m);
For (i,m){
scanf("%d%d%d %c",&x,&y,&z,&ch);
add(x,y,z);
add(y,x,z);
}
scanf("%d",&k);
f[0]=size=n;
findroot(1,0);
work(root);
printf("%d",ans);

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