1316: 树上的询问(点分治)
Posted HWIM
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1316: 树上的询问(点分治)相关的知识,希望对你有一定的参考价值。
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: 树上的询问(点分治)的主要内容,如果未能解决你的问题,请参考以下文章