在一顆n個結點的樹上,統計有多少點對最短距離<=m。(點對不存在順序性)n<=10000
我們選取乙個點x作根,那麼任何點對都分成兩種型別
1、經過x
2、不經過x
我們對經過x的進行統計,對於不經過x的繼續在x的子樹中分治下去。這就是點分治。
我們處理出每個點的深度,排序後就很容易統計經過x的個數。
不過有可能出現一對點對的lca是y而不是x,然後他們被統計進去了,要在往下分治的過程中減去他們。
為了使分治樹不退化,每次選取重心充當根,那麼最多log n層,每一層點總和不超過n,複雜度為n log n。
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=10000+10;
int d[maxn],s[maxn],h[maxn],go[maxn*2],next[maxn*2],dis[maxn*2],a[maxn];
bool bz[maxn];
int i,j,k,l,t,n,m,tot,ans,top;
void add(int
x,int
y,int z)
void dfs(int
x,int
y) t=next[t];
}}void dg(int
x,int
y) t=next[t];
}}bool cmp(int
x,int
y)void solve(int
x) if (i==j) i--;
ans-=i;}}
j=x;k=0;
while (1)
t=next[t];
}if (!t) break;
}d[j]=0;
dg(j,0);
sort(a+1,a+top+1,cmp);
i=0;k=j;
fd(j,top,1)
if (i==j) i--;
ans+=i;
}t=h[k];
bz[k]=1;
while (t)
}int main()
solve(1);
printf("%d\n",ans);
}
樹中點對距離(點分治)
給出一棵帶邊權的樹,問有多少對點的距離 len 這是一道點分治的經典題目,可以給點分治的初學者練手。點分治,顧名思義就是把每個點分開了處理答案。假設,目前做到了以x為根的子樹。先求出子樹中每個點到根的距離di s 對於兩個點 i 和 j,如果di si d isj k 那麼 i j 就是乙個合法的點...
點分治模板 (樹中點對距離)
點分治就是在一棵樹中,將每個點分治 基本概念 點分治 將一棵無根樹變成有根樹,再分別處理每棵有根子樹。重心 在一棵樹中,這個點的最大子樹是所有點中最小的。也可以說是刪除該點時,樹內剩下的子樹最大節點數最小。size i 表示以i為根的子樹節點數量。如何求重心?求出size,什麼是定義,就怎麼求。一般...
JZOJ 1166 樹中點對距離
給出一棵帶邊權的樹,問有多少對點的距離 le n 2 n 10000 len 231 這是一道十分經典的點分治題目。點分治,顧名思義,就是按照點來分治。假設當前要計算某棵子樹裡面滿足題目條件的點對數,我們可以先找出這棵子樹的重心。易知,此棵子樹的點對數 經過重心的合法點對數 不經過重心的合法點對數。...