水題一道----奶牛政壇

水題—-奶牛政壇

題目如下:

問題描述

農夫約翰的奶牛住在N (2 <= N <= 200,000)片不同的草地上,標號爲1到N。恰好有N-1條單位長度的雙向道路,用各種各樣的方法連接這些草地。而且從每片草地出發都可以抵達其他所有草地。也就是說,這些草地和道路構成了一種叫做樹的圖。

輸入包含一個詳細的草地的集合,詳細說明了每個草地的父節點P_i (0 <= P_i <= N)。根節點的P_i == 0, 表示它沒有父節點。因爲奶牛建立了1到K一共K (1 <= K <= N/2)個政黨。每隻奶牛都要加入某一個政黨,其中,第i只奶牛屬於第A_i (1 <= A_i <= K)個政黨。而且每個政黨至少有兩隻奶牛。這些政黨互相吵鬧爭。每個政黨都想知道自己的“範圍”有多大。其中,定義一個政黨的範圍是這個政黨離得最遠的兩隻奶牛(沿着雙向道路行走)的距離。比如說,記爲政黨1包含奶牛1,3和6,政黨2包含奶牛2,4和5。

這些草地的連接方式如下圖所示(政黨1由-n-表示):政黨1最大的兩隻奶牛的距離是3(也就是奶牛3和奶牛6的距離)。政黨2最大的兩隻奶牛的距離是2(也就是奶牛2和4,4和5,還有5和2之間的距離)。幫助奶牛們求出每個政黨的範圍。

輸入格式

第一行: 兩個由空格隔開的整數: N 和 K

第2到第N+1行: 第i+1行包含兩個由空格隔開的整數: A_i和P_i

輸出格式

第1到第K行: 第i行包含一個單獨的整數,表示第i個政黨的範圍。

數據規模

見問題描述

題解如下:

這就是一道大水題,我們只需要預處理出每個政黨深度最深的點,然後掃一遍所有的點,用該點到對應政黨最深點的距離更新該政黨的範圍即可。其實每個政黨是散佈在整個樹中的,給人一種虛樹的感覺。如果對於每個政黨構建一顆虛樹,那麼深度最深的點一定是虛樹的某條直徑的某個端點,所以到該點的最遠距離即是虛樹的直徑長度。其實根節點不一定在虛樹中,但是把根節點加入虛樹是沒有影響的,這就是爲什麼我們可以直接處理深度最深的點.

這道題如果用點分治的話就是一個模板題。我寫了一份點分治的代碼,放在下面:

#include<cstdio> 
#include<algorithm> 
using namespace std; 
#define MAXN 855000 
int st[MAXN],top; 
int size[MAXN],vis[MAXN],c[MAXN],rt; 
int Next[MAXN],End[MAXN],Last[MAXN],e=1; 
void add(int x,int y) 
{ 
    End[++e]=y; 
    Next[e]=Last[x]; 
    Last[x]=e; 
    return ; 
} 
void _r(int& x) 
{ 
    char c=getchar(); 
    while(c<'0'||c>'9') 
    { 
        c=getchar(); 
    } 
    for(x=0;c>='0'&&c<='9';c=getchar()) 
    { 
        x=(x<<1)+(x<<3)+c-'0'; 
    } 
    return ; 
} 
int get(int p,int summ,int fa) 
{ 
    int sz=0,total=0,ch=0; 
    for(int t=Last[p],q;t;t=Next[t]) 
    { 
        q=End[t]; 
        if(vis[q]||q==fa) 
        { 
            continue; 
        } 
        if(size[q]>sz) 
        { 
            sz=size[q]; 
            ch=q; 
        } 
        total+=size[q]; 
    } 
    if(sz>(summ>>1)) 
    { 
        return get(ch,summ,p); 
    } 
    else 
    { 
        return p; 
    } 
} 
const int inf=0x1fffffff; 
int cur[MAXN],dis[MAXN],Ans[MAXN]; 
void solve(int p,int fa) 
{ 
    size[p]=1; 
    for(int t=Last[p];t;t=Next[t]) 
    { 
        if(!vis[End[t]]&&End[t]!=fa) 
        { 
            solve(End[t],p); 
            size[p]+=size[End[t]]; 
        } 
    } 
    dis[c[p]]=-inf; 
    return ; 
} 
void cal(int p,int fa,int dep) 
{ 
    int h=c[p]; 
    st[++top]=p; 
    Ans[h]=max(Ans[h],dis[h]+dep); 
    cur[h]=max(cur[h],dep); 
    for(int t=Last[p];t;t=Next[t]) 
    { 
        if(!vis[End[t]]&&End[t]!=fa) 
        { 
            cal(End[t],p,dep+1); 
        } 
    } 
    return ; 
} 
void dfs(int p) 
{ 
    solve(p,0); 
    p=get(p,size[p],0); 
    vis[p]=1; 
    dis[c[p]]=0; 
    for(int t=Last[p],q;t;t=Next[t]) 
    { 
        q=End[t]; 
        if(!vis[q]) 
        { 
            cal(q,p,1); 
            for(int s;top;--top) 
            { 
                s=c[st[top]]; 
                dis[s]=max(dis[s],cur[s]); 
                cur[s]=-inf; 
            } 
        } 
    } 
    for(int t=Last[p],q;t;t=Next[t]) 
    { 
        if(!vis[End[t]]) 
        { 
            dfs(End[t]); 
        } 
    } 
    return ; 
} 
int n,k; 
int main() 
{ 
    _r(n); 
    _r(k); 
    for(int i=1,x;i<=n;i++) 
    { 
        _r(c[i]); 
        _r(x); 
        if(x==0) 
        { 
            rt=i; 
        } 
        else 
        { 
            add(x,i); 
            add(i,x); 
        } 
    } 
    for(int i=1;i<=k;i++) 
    { 
        Ans[i]=0; 
    } 
    dfs(rt); 
    for(int i=1;i<=k;i++) 
    { 
        printf("%d\n",Ans[i]); 
    } 
    return 0; 
}

點分治就是一個大暴力!

發佈了31 篇原創文章 · 獲贊 6 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章