bzoj1468 tree 点分治

来源:互联网 发布:如何访问mpp数据库 编辑:程序博客网 时间:2024/05/01 12:16

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

计算经过根的路径,既离根的距离之和小于K的点,然后递归处理不经过根的路径。这样会有一些重复,两点与根的距离之和小于K,但是路径不经过根,需要减掉。

#include<iostream>#include<cstdio>#include<algorithm>#define maxn 80005using namespace std;struct E{    int to,nxt,d;}b[100005];int fst[maxn],tot=1;void insert(int f,int t,int d){    b[++tot]=(E){t,fst[f],d};fst[f]=tot;    b[++tot]=(E){f,fst[t],d};fst[t]=tot;}int size[maxn],mx[maxn];bool vis[maxn];int dis[maxn];int root,sum,K,ans,top;int a[maxn];void dfs(int x,int f){    size[x]=1;mx[x]=0;    for(int i=fst[x];i;i=b[i].nxt)    {        int v=b[i].to;        if(v!=f&&!vis[v])        {            dfs(v,x);            size[x]+=size[v];            mx[x]=max(mx[x],size[v]);        }    }    mx[x]=max(mx[x],sum-size[x]);    if(mx[x]<mx[root]) root=x;}void get_dis(int x,int f){    a[++top]=dis[x];    for(int i=fst[x];i;i=b[i].nxt)    {        int v=b[i].to;        if(v!=f&&!vis[v])        {            dis[v]=dis[x]+b[i].d;            get_dis(v,x);        }    }}int cal(int x,int now){    dis[x]=now;top=0;    get_dis(x,0);    sort(a+1,a+top+1);    int ans=0,l=1,r=top;    while(l<r)        if(a[l]+a[r]<=K)            ans+=r-l,l++;        else r--;    return ans;}void solve(int x){    ans+=cal(x,0);    vis[x]=1;    for(int i=fst[x];i;i=b[i].nxt)    {        int v=b[i].to;        if(!vis[v])        {            ans-=cal(v,b[i].d);            sum=size[v];            root=0;dfs(v,0);            solve(root);        }    }}int main(){    mx[0]=maxn;    int n;    scanf("%d",&n);    int u,v,d;    for(int i=1;i<n;i++)    {        scanf("%d%d%d",&u,&v,&d);        insert(u,v,d);    }    scanf("%d",&K);    sum=n; root=0;    dfs(1,0);    solve(root);    cout<<ans;    return 0;}
1 0
原创粉丝点击