點分治【bzoj1468】 Tree

來源:互聯網
上載者:User

標籤:print   ret   tree   algo   最小   樹形dp   ons   接下來   turn   

點分治【bzoj1468】 Tree
Description

給你一棵TREE,以及這棵樹上邊的距離.問有多少對點它們兩者間的距離小於等於K

Input

N(n<=40000) 接下來n-1行邊描述管道,按照題目中寫的輸入 接下來是k

Output

一行,有多少對點之間的距離小於等於k

點分治開始入門。

點分治,主要是解決形如:給你一棵樹,求樹上滿足XX條件的點對的對數。

所以說應對的問題很多時候都和樹形DP相同。

首先告訴自己,分治是高效的演算法。

想一下,平時在面對普通的分治問題,每次肯定都是半分,直到成為小問題,然後再分別解決。

為了保證點分治的高效,所以我們每一次應該將當前問題分成最平均的兩個問題,放到樹上就是指我們要將當前的樹分成大小最平均的幾棵。

那麼就可以引入一個概念:樹的重心。定義是在樹上找一個點作為根,使得子樹中的size最大者最小,這樣我們就可以很好的將樹平均分。

所以解決點分治問題的基本思路也就有了:

? 我們從整棵樹開始,每一次找到當前樹的重心並且以他為根,也就是將無根樹轉成有根樹,然後對於當前的樹,我們只對與當前樹的根的點對進行處理。

? 對於這道題來說,就是找到路徑經過當前根的點對,去統計這些點對中合格數量對答案作出貢獻。

? 然後對於每個子樹,向下分治,繼續找重心……

code

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int wx=40017;inline int read(){    int sum=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}    return sum*f;}int n,m,ans,num,root,k,tmp;int head[wx],dis[wx],size[wx];int f[wx],vis[wx];int temp[wx];struct e{    int nxt,to,dis;}edge[wx*2];void add(int from,int to,int dis){    edge[++num].nxt=head[from];    edge[num].to=to;    edge[num].dis=dis;    head[from]=num;}void getroot(int u,int fa){    size[u]=1;f[u]=0;    for(int i=head[u];i;i=edge[i].nxt){        int v=edge[i].to;        if(v==fa||vis[v])continue;        getroot(v,u);        size[u]+=size[v];        f[u]=max(f[u],size[v]);    }    f[u]=max(f[u],tmp-size[u]);    if(f[root]>f[u])root=u;}void dfs(int u,int fa){    temp[++temp[0]]=dis[u];    for(int i=head[u];i;i=edge[i].nxt){        int v=edge[i].to;        if(v==fa||vis[v])continue;dis[0]++;        dis[v]=dis[u]+edge[i].dis;        dfs(v,u);    }}int calc(int u,int now){    dis[u]=now;temp[0]=0;dfs(u,0);    int l=1,r=temp[0];int re=0;    sort(temp+1,temp+temp[0]+1);    while(l<r){        if(temp[r]+temp[l]<=k)re+=r-l,l++;        else r--;    }    return re;}void slove(int u){    vis[u]=1;ans+=calc(u,0);    for(int i=head[u];i;i=edge[i].nxt){        int v=edge[i].to;        if(vis[v])continue;        ans-=calc(v,edge[i].dis);        root=0;tmp=size[v];getroot(v,0);slove(root);    }}int main(){    n=read();    for(int i=1;i<n;i++){        int x,y,z;        x=read();y=read();z=read();        add(x,y,z);add(y,x,z);    }    k=read();    f[0]=(1<<30);tmp=n;    getroot(1,0);    slove(root);    printf("%d\n",ans);    return 0;}

點分治【bzoj1468】 Tree

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.