bzoj2599: [IOI2011]Race

http://www.lydsy.com/JudgeOnline/problem.php?id=2599

 

点分治

mi[i] 记录边权和为i时的最少边数

先更新答案,再更新mi数组,换根时清空mi

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>

using namespace std;

#define N 200001
#define K 1000001

int m;

int front[N],nxt[N<<1],to[N<<1],tot,val[N<<1];

bool vis[N];

int f[N],siz[N];

int root,all;
int ans=N;

int mi[K];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c))  { x=x*10+c-'0'; c=getchar(); }
}

void add(int u,int v,int w)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w;
}

void getroot(int x,int y)
{
    //printf("%d\n",x);
    siz[x]=1; f[x]=0;
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=y && !vis[to[i]]) 
        {
            getroot(to[i],x);
            siz[x]+=siz[to[i]];
            f[x]=max(f[x],siz[to[i]]);
        }
    f[x]=max(f[x],all-siz[x]);
    if(f[x]<f[root]) root=x;
}

void dfs(int x,int y,int dis,int sum,int ty)
{
    if(ty==1 && dis==m) ans=min(ans,sum);
    if(dis>=m) return;
    if(ty==1)
    {
        if(mi[m-dis]) ans=min(ans,sum+mi[m-dis]);
    }
    else if(ty==2) mi[dis]=mi[dis] ? min(mi[dis],sum) : sum;
    else mi[dis]=0;
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=y && !vis[to[i]]) dfs(to[i],x,dis+val[i],sum+1,ty);
}

void cal(int x)
{
    for(int i=front[x];i;i=nxt[i])
        if(!vis[to[i]]) 
        {
            dfs(to[i],x,val[i],1,1);
            dfs(to[i],x,val[i],1,2);
        }
    for(int i=front[x];i;i=nxt[i])
        if(!vis[to[i]]) dfs(to[i],x,val[i],1,3);
}

void work(int x)
{
//    printf("%d\n",x);
    cal(x);
    vis[x]=true;
    for(int i=front[x];i;i=nxt[i])    
        if(!vis[to[i]])
        {
            all=siz[to[i]];
            root=0;
            getroot(to[i],0);
            work(root);
        }
}

int main()
{
    int size = 128 << 20;
    char *p = (char*)malloc(size) + size;  
    __asm__("movl %0, %%esp\n" :: "r"(p));
    freopen("ioi2011-race.in","r",stdin);
    freopen("ioi2011-race.out","w",stdout);
    int n;
    read(n);
    read(m);
    int u,v,w;
    for(int i=1;i<n;++i)
    {
        read(u); u++;
        read(v); v++;
        read(w);
        add(u,v,w);    
    }
    all=n;
    f[0]=n;
    getroot(1,0);
    work(root);
    printf("%d",ans==N ? -1 : ans);
}
posted @ 2017-12-28 15:57  TRTTG  阅读(364)  评论(0编辑  收藏  举报