【BZOJ4016】【FJOI2014】 最短路径树问题 树的点分治

首先是最短路径树,将一个点相连的所有边装入Vector中,排序后倒序加边(因为链表的写法是从最后加入的边向前便利),求出最短路径图后DFS得到最短路径树,然后和普通的点分治一样辣!

要善于利用时间戳(虽然并没有什么卵用)。

#include<cstdlib>  
#include<cstdio>  
#include<iostream>  
#include<cstring>  
#include<cmath>  
#include<algorithm>  
#include<queue>  
#include<vector>  
using namespace std;  
#define maxn 60005  
#define oo 999999999  
struct edge  
{  
    int to,d,next;bool ban;  
}e[maxn*5],e2[maxn*5];  
    
struct _pa{int y,d;};  
vector<_pa>To[maxn];  
bool operator < (_pa x,_pa y)  
{  
    return x.y<y.y;  
}  
void _read(int &x)  
{  
    bool flag=false; 
    x=0; char ch=getchar();  
    while(ch<'0'||ch>'9'){if(ch=='-')flag=true; ch=getchar();} 
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}  
    if(flag)x=-x; 
    return ;  
}  
    
  
int edge_ct,n,m,k,edge_ct2,head2[maxn],head[maxn],d[maxn];  
bool v[maxn];  
void add2(int x,int y,int z)  
{  
    e2[++edge_ct2]=(edge){y,z,head2[x],false};head2[x]=edge_ct2;  
    return ;  
}  
void add(int x,int y,int z)  
{  
    e[++edge_ct]=(edge){y,z,head[x],false};head[x]=edge_ct;  
    e[++edge_ct]=(edge){x,z,head[y],false};head[y]=edge_ct;  
    return ;  
}  
struct data 
{ 
    int x,y; 
}; 
struct cmp 
{ 
    bool operator () (data x,data y) 
    { 
        return x.y>y.y; 
    } 
}; 
priority_queue<data ,vector<data>,cmp>pq; 
void Dijkstra()  
{   
    d[1]=0; 
    for(int i=2;i<=n;i++)d[i]=oo;  
    for(int i=1;i<=n;i++)v[i]=false;  
     
    pq.push((data){1,0}); 
    data t; 
    int i,id,j; 
    while(!pq.empty()) 
    { 
        t=pq.top(); pq.pop();if(v[t.x])continue; 
        i=t.x; v[i]=true; 
        for(int id=head2[i];id;id=e2[id].next) 
        { 
            j=e2[id].to; 
            if(d[j]<=d[i]+e2[id].d)continue; 
            d[j]=d[i]+e2[id].d; 
            pq.push((data){j,d[j]}); 
        } 
    } 
    return ;  
}  
void DFS_1(int now)  
{  
    v[now]=true;  
    int j;  
    for(int id=head2[now];id;id=e2[id].next)  
    {  
        j=e2[id].to;  
        if((v[j]) || d[j]!=d[now]+e2[id].d)continue;  
        add(now,j,e2[id].d);  
    //  printf("%d %d\n",now,j);  
        DFS_1(j);  
    }  
    return ;  
}  
void Init()  
{  
    _read(n);_read(m);_read(k);k--;  
    int x,y,z;  
    edge_ct2=edge_ct=0;  
    for(int i=1;i<=m;i++)  
    {  
        _read(x); _read(y); _read(z);  
        To[x].push_back((_pa){y,z});  
        To[y].push_back((_pa){x,z});  
    }  
    for(int i=1;i<=n;i++)  
    {  
    //  printf("%d:\n",i);  
        sort(To[i].begin(),To[i].end());  
        for(int j=To[i].size()-1;j>=0;j--)  
        {  
            add2(i,To[i][j].y,To[i][j].d);  
    //      printf("%d %d\n",To[i][j].y,To[i][j].d);  
        }  
    }  
    Dijkstra();  
    for(int i=1;i<=n;i++)v[i]=false;  
    edge_ct=0; 
    DFS_1(1);  
    return ;  
}  
int sz[maxn],cc[maxn],gc;  
void get_gc(int now,int fa,int size)  
{  
    sz[now]=1;cc[now]=0;  
    for(int id=head[now];id;id=e[id].next)  
    {  
        int j=e[id].to;  
        if(e[id].ban || j==fa || v[e[id].to])continue;  
        get_gc(j,now,size);  
        cc[now]=max(cc[now],sz[j]);
        sz[now]+=sz[j];  
    }  
    if(size-cc[now]>cc[now])cc[now]=size-cc[now];  
    if(cc[now]<cc[gc])gc=now;  
    return ;  
}  
int dp[maxn],dpct[maxn],_time,Maxdep;  
int dp1[maxn],dpct1[maxn];  
int ans1,ans2;  
void DFS_2(int now,int fa,int de,int sum)  
{  
    sz[now]=1;  
    if(de>Maxdep)  
    {  
        Maxdep=de; dp1[de]=sum; dpct1[de]=1;  
    }  
    else
    {  
        if(dp1[de]==sum)dpct1[de]++;  
        else if(dp1[de]<sum)  
        {  
            dp1[de]=sum; dpct1[de]=1;  
        }  
    }  
    for(int id=head[now];id;id=e[id].next)  
    {  
        if(e[id].ban || e[id].to==fa || v[e[id].to])continue;  
        DFS_2(e[id].to,now,de+1,sum+e[id].d);  
        sz[now]+=sz[e[id].to];  
    }  
    return ;  
}  
int T[maxn]; 
void calc(int now,int sz)  
{  
      
    dp[0]=0; dpct[0]=1;  
    _time++;T[0]=_time; 
    //for(int i=1;i<=k;i++){dp[i]=-1;dpct[i]=0;} 
    for(int id=head[now];id;id=e[id].next)  
    {  
        if(e[id].ban || v[e[id].to])continue;  
        Maxdep=0;  
        DFS_2(e[id].to,now,1,e[id].d);  
        for(int i=Maxdep;i>=1;i--)  
        {  
            if(k-i<0)continue;  
            if(T[k-i]<_time) 
            { 
                dp[k-i]=-1; dpct[k-i]=0; T[k-i]=_time; 
            } 
            if(ans1<dp1[i]+dp[k-i])  
            {  
                ans1=dp1[i]+dp[k-i]; ans2=dpct[k-i]*dpct1[i];  
            }  
            else if(ans1 == dp1[i]+dp[k-i])ans2+=dpct[k-i]*dpct1[i];  
        }  
        for(int i=Maxdep;i>=1;i--)  
        {  
            if(i>k)continue;  
            if(T[i]<_time) 
            { 
                dp[i]=-1; dpct[i]=0; T[i]=_time; 
            } 
            if(dp[i]<dp1[i])  
            {  
                dp[i]=dp1[i]; dpct[i]=dpct1[i];  
            }  
            else if(dp[i]==dp1[i])  
            {  
                dpct[i]+=dpct1[i];  
            }  
        }  
    }  
    return ;  
}  
void Tree_Devide(int now,int size)  
{  
    gc=0;cc[0]=oo;  
    get_gc(now,0,size);  
    if(gc==0)gc=now;  
    calc(gc,size);  
    v[gc]=1;
    for(int id=head[gc];id;id=e[id].next)if(!e[id].ban && !v[e[id].to])  
    {  
        e[id].ban=e[id+(id%2==0 ? -1 : 1)].ban=true;  
        if(sz[e[id].to]>=k)Tree_Devide(e[id].to,sz[e[id].to]);  
    }        
    return ;  
}  
void work()  
{  
    ans1=-oo; ans2=0;  
    _time=0; 
    memset(v,0,sizeof(v));
    Tree_Devide(1,n);  
    printf("%d %d\n",ans1,ans2);  
    return ;  
}  
int main()  
{  
    freopen("in.txt","r",stdin);  
    Init();  
    work();  
    return 0;  
} 


 

你可能感兴趣的:(【BZOJ4016】【FJOI2014】 最短路径树问题 树的点分治)