1. 程式人生 > >[cdq分治][樹的重心] 洛谷 P3806 點分治1

[cdq分治][樹的重心] 洛谷 P3806 點分治1

class 說明 queue math reg rdquo adg reset badge

題目描述

給定一棵有n個點的樹

詢問樹上距離為k的點對是否存在。

輸入輸出格式

輸入格式:

n,m 接下來n-1條邊a,b,c描述a到b有一條長度為c的路徑

接下來m行每行詢問一個K

輸出格式:

對於每個K每行輸出一個答案,存在輸出“AYE”,否則輸出”NAY”(不包含引號)

輸入輸出樣例

輸入樣例#1:
2 1
1 2 2
2
輸出樣例#1:
AYE

說明

對於30%的數據n<=100

對於60%的數據n<=1000,m<=50

對於100%的數據n<=10000,m<=100,c<=1000,K<=10000000

代碼

  • 對於一條x到y的路徑有可能有兩種情況,
  • ①要經過根節點,那麽這樣的距離就是dis[u]+dis[v](到根的距離)
  • ②在一個子樹中,那麽就找到該子樹的根,然後就類似於第一種情況
  • 其實就是分治的思想,把樹不斷分解成子樹然後求解
  • 點分治過程中,每一層的所有遞歸過程合計對每個點處理一次, 假設共遞歸T層,則總時間復雜度為O(TNlogN)
  • 然而,如果樹退化成一條鏈, 那麽遞歸層數就是T=n,總時間復雜度為O(N^2logN)
  • 這樣的復雜度接受不了,那麽就要減少樹的層數,那麽每次就要找到樹的中心來作為根,這樣才能減少層數
  • 然後就是點分治了

代碼

 1 #include <cstdio> 
 2
#include <iostream> 3 #include <queue> 4 #include <vector> 5 using namespace std; 6 const int inf=10000000; 7 const int N=100010; 8 struct edge{int to,from,v;}e[N*2]; 9 int n,m,num,root,ans,cnt,head[N],mx[N],size[N],dis[N],dfn[N],vis[N],g[inf],w[inf],p[N],k[1010]; 10 void insert(int
x,int y,int z) { e[++cnt].to=y; e[cnt].from=head[x]; e[cnt].v=z; head[x]=cnt; } 11 void getroot(int x,int fa) 12 { 13 size[x]=1,mx[x]=0; 14 for (int i=head[x];i;i=e[i].from) 15 if (e[i].to!=fa&&!vis[e[i].to]) 16 { 17 getroot(e[i].to,x); 18 size[x]+=size[e[i].to]; 19 mx[x]=max(mx[x],size[e[i].to]); 20 } 21 mx[x]=max(mx[x],num-size[x]); 22 if (mx[x]<mx[root]) root=x; 23 } 24 void getdis(int x,int fa) 25 { 26 dfn[++dfn[0]]=dis[x]; 27 for (int i=head[x];i;i=e[i].from) 28 if (e[i].to!=fa&&!vis[e[i].to]) 29 dis[e[i].to]=dis[x]+e[i].v,getdis(e[i].to,x); 30 } 31 void work(int x) 32 { 33 p[0]=0; 34 for (int i=head[x];i;i=e[i].from) 35 if (!vis[e[i].to]) 36 { 37 dis[e[i].to]=e[i].v,dfn[0]=0; 38 getdis(e[i].to,x); 39 for (int j=dfn[0];j;j--) 40 for (int q=1;q<=m;q++) 41 if (k[q]>=dfn[j]) g[q]|=w[k[q]-dfn[j]]; 42 for (int j=dfn[0];j;j--) p[++p[0]]=dfn[j],w[dfn[j]]=1; 43 } 44 for (int i=1;i<=p[0];i++) w[p[i]]=0; 45 } 46 void cdq(int x) 47 { 48 vis[x]=w[0]=1,work(x); 49 for (int i=head[x];i;i=e[i].from) 50 if (!vis[e[i].to]) 51 num=size[e[i].to],mx[root=0]=inf,getroot(e[i].to,0),cdq(root); 52 } 53 int main() 54 { 55 scanf("%d%d",&n,&m); 56 for (int i=1,x,y,z;i<n;i++) scanf("%d%d%d",&x,&y,&z),insert(x,y,z),insert(y,x,z); 57 for (int i=1;i<=m;i++) scanf("%d",&k[i]); 58 mx[root]=num=n,getroot(1,0),cdq(root); 59 for (int i=1;i<=m;i++) if (g[i]) printf("AYE\n"); else printf("NAY\n"); 60 }

[cdq分治][樹的重心] 洛谷 P3806 點分治1