1. 程式人生 > >1316: 樹上的詢問(點分治)

1316: 樹上的詢問(點分治)

pan CA tps void head 分析 git HA 不能

1316: 樹上的詢問

鏈接

分析

  每次查找出重心(去掉重心後的最大的聯通塊最小,保證復雜度),然後統計過重心的路徑中有沒有長度等於len的。

  統計時,由於必須要過重心,不能是同一棵子樹中的。可以挨個遍歷每棵子樹,然後統計即可。

  判斷時,用set查找一下即可。

代碼

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cctype>
  4 #include<set>
  5  
  6 using namespace std;
  7
8 const int N = 10010; 9 10 struct Edge{ 11 int to,nxt,w; 12 Edge() {} 13 Edge(int a,int b,int c) {to = a,w = b,nxt = c;} 14 }e[N<<1]; 15 int A[N],q[N],ans[N],dis[N],deth[N],head[N],siz[N]; 16 int tot,Root,Size,Cnt,Num = 1e9,n,m; 17 bool vis[N]; 18 set<int
>s; 19 20 inline int read() { 21 int x = 0,f = 1;char ch=getchar(); 22 for (; !isdigit(ch); ch=getchar()) if(ch==-)f=-1; 23 for (; isdigit(ch); ch=getchar()) x=x*10+ch-0; 24 return x*f; 25 } 26 void add_edge(int u,int v,int w) { 27 e[++tot] = Edge(v,w,head[u]);head[u] = tot;
28 e[++tot] = Edge(u,w,head[v]);head[v] = tot; 29 } 30 void getRoot(int u,int fa) { 31 siz[u] = 1; 32 int mx = 0; 33 for (int i=head[u]; i; i=e[i].nxt) { 34 int v = e[i].to; 35 if (v == fa || vis[v]) continue; 36 getRoot(v,u); 37 siz[u] += siz[v]; 38 mx = max(siz[v],mx); 39 } 40 mx = max(mx,Size-siz[u]); 41 if (mx < Num) Root = u,Num = mx; 42 } 43 void dfs(int u,int fa) { 44 A[++Cnt] = dis[u]; 45 for (int i=head[u]; i; i=e[i].nxt) { 46 int v = e[i].to; 47 if (v == fa || vis[v]) continue; 48 dis[v] = dis[u] + e[i].w; 49 dfs(v,u); 50 } 51 } 52 void calcc(int u) { 53 s.clear(); 54 s.insert(0); 55 dis[u] = 0; 56 for (int i=head[u]; i; i=e[i].nxt) { 57 int v = e[i].to; 58 if (vis[v]) continue; 59 Cnt = 0; 60 dis[v] = e[i].w; 61 dfs(v,u); 62 for (int j=1; j<=Cnt; ++j) { 63 for (int k=1; k<=m; ++k) { 64 if (ans[k]) continue; 65 if (s.find(q[k]-A[j])!=s.end()) ans[k] = 1; 66 } 67 } 68 for (int j=1; j<=Cnt; ++j) s.insert(A[j]); 69 } 70 } 71 void solve(int u) { 72 vis[u] = true; 73 calcc(u); 74 for (int i=head[u]; i; i=e[i].nxt) { 75 int v = e[i].to; 76 if (vis[v]) continue; 77 Size = siz[v];Num = 1e9;Root = 0; 78 getRoot(v,0); 79 solve(Root); 80 } 81 } 82 int main() { 83 n = read(),m = read(); 84 for (int u,v,w,i=1; i<n; ++i) { 85 u = read(),v = read(),w = read(); 86 add_edge(u,v,w); 87 } 88 for (int i=1; i<=m; ++i) { 89 q[i] = read(); 90 if (!q[i]) ans[i] = 1; 91 } 92 Size = n; 93 Num = 1e9; 94 getRoot(1,0); 95 solve(Root); 96 for (int i=1; i<=m; ++i) 97 if (ans[i]) puts("Yes"); 98 else puts("No"); 99 return 0; 100 }

1316: 樹上的詢問(點分治)