BZOJ2599: [IOI2011]Race

【传送门:BZOJ2599


简要题意:

  给出一棵n个点的树,和每条边的边权

  求出所有距离为k的点对中,两个点之间的最少边数


题解:

  点分治好题

  设c[i]为当前点分治的时候与根的距离为i的最小边数

  因为我们不能使得求出来的点对都在一棵子树里面,所以我们枚举每一棵与根相连的子树,每次求出对于这棵子树的c数组

  然后再DFS一遍,更新答案

  听说不能用memset来初始化c,那么就DFS将用过的位置初始化


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define INF 1<<31-1
using namespace std;
struct node
{
    int x,y,d,next;
}a[410000];int len,last[210000];
void ins(int x,int y,int d)
{
    len++;
    a[len].x=x;a[len].y=y;a[len].d=d;
    a[len].next=last[x];last[x]=len;
}
int tot[210000],root,sum,ms[210000];
bool v[210000];
void getroot(int x,int fa)
{
    tot[x]=1;ms[x]=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa&&v[y]==false)
        {
            getroot(y,x);
            tot[x]+=tot[y];
            ms[x]=max(ms[x],tot[y]);
        }
    }
    ms[x]=max(ms[x],sum-tot[x]);
    if(ms[root]>ms[x]) root=x;
}
int ans,k;
int c[1100000];
int dep[210000],d[210000];
void cal(int x,int fa)
{
    if(d[x]<=k) ans=min(ans,c[k-d[x]]+dep[x]);
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa&&v[y]==false)
        {
            dep[y]=dep[x]+1;
            d[y]=d[x]+a[k].d;
            cal(y,x);
        }
    }
}
void change(int x,int fa,int t)
{
    if(d[x]<=k)
    {
        if(t==0) c[d[x]]=min(c[d[x]],dep[x]);
        else c[d[x]]=INF;
    }
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa&&v[y]==false)
        {
            change(y,x,t);
        }
    }
}
void solve(int x)
{
    v[x]=true;c[0]=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(v[y]==false)
        {
            dep[y]=1;d[y]=a[k].d;
            cal(y,0);
            change(y,0,0);
        }
    }
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(v[y]==false)
        {
            change(y,0,1);
        }
    }
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(v[y]==false)
        {
            sum=tot[y];
            root=0;getroot(y,x);
            solve(root);
        }
    }
}
int main()
{
    int n;
    scanf("%d%d",&n,&k);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<n;i++)
    {
        int x,y,d;
        scanf("%d%d%d",&x,&y,&d);
        x++;y++;
        ins(x,y,d);ins(y,x,d);
    }
    memset(v,false,sizeof(v));
    memset(c,63,sizeof(c));c[0]=0;
    ans=sum=ms[0]=n;
    root=0;getroot(1,0);
    solve(root);
    if(ans!=n) printf("%d\n",ans);
    else printf("-1\n");
    return 0;
}

 

posted @ 2018-04-27 20:56  Star_Feel  阅读(207)  评论(0编辑  收藏  举报